Documente Academic
Documente Profesional
Documente Cultură
date la olimpiade
în
2020
2019 2018 2017 2016 2015
2014 2013 2012 2011 2010
la I.O.I.
9 decembrie 2020
Dedicaµie
1
to myself ...
in a time when ...
I will not be able ...
2
to be.
3
When I Die Nobody Will Remember Me
1
I Dedicate This Book to Myself By Carol Lynne
2
To be, or not to be ..., Hamlet, Act III, Scene I, William Shakespeare, 1564-1616
3
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 ecare dat , nu îl poµi ajuta? Eu cred c nu este prea
bine ³i poate c ... te faci ... de râs! Pe vremea mea (!), când eram elev de gimnaziu, un student
era ca un fel de ... zeu! Cu trecerea anilor am înµeles c nu este chiar a³a! i înc ceva: nu am
reu³it s înµeleg de ce, atunci când cineva nu poate s rezolve corect o problem de informatic
de clasa a 6-a, dat la olimpiada de informatic sau ca tem de cas , folose³te aceast scuz : eu
nu am f cut informatic în liceu! ³i acest cineva este zeul sau zeiµa despre care vorbeam!.
4
Sunt convins c este important s studiem cu atenµie cât mai multe probleme rezolvate! Cred
cred c sunt utile ³i primele versiuni în care sunt prezentate chiar ³i numai enunµurile ³i indicaµiile
"ociale" de rezolvare. Acestea se g sesc în multe locuri; aici încerc s le pun pe toate la un loc !
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
5 6
dicil ! :-) 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
7
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 posibil ...
a³a c , de aceast dat , anii sunt în ordine ... descresc toare! :-)
Codurile surs sunt cele ociale (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
disponibil ³i, oricum, calculatoarele folosite la olimpiade înainte de 2010 erau ceva mai 'slabe' ³i
8
... restricµiile de memorie, din enunµurile problemelor, par 'ciudate' acum!). i indc a venit
vorba despre calculatoare mai slabe sau mai puternice: laptopul meu¯t u este puµin mai slab
decât cel mai puternic calculator din lume în 1985 dar ³i ... un pic mai puternic decât cel mai
9
puternic calculator din lume în 1983. (armaµia este valabil acum, în 2020).
4
Se poate observa din Coduri surs c orice problem are numeroase soluµii, atât ca algoritmi de rezolvare
cât ³i ca stil de programare! Studiind aceste coduri ... avem ce înv µa ... de³i uneori pare c 'se trage cu tunul' ...
5
IOI2019 ³i IOI2020 au a permis utilizarea limbajelor de programare C++ ³i Java
6
IOI2015 a permis utilizarea limbajelor de programare C++, Java, Pascal, Python ³i Rubi (...)
7
8
Vezi cele 5 secunde pentru Timp maxim de executare/test din problema avârcolaci - ONI2014 clasa a 11-a
Când eram eu elev/student un calculator obi³nuit executa în jur de 1.000.000 de operaµii pe secund , acum
execut 1.000.000.000 de operaµii pe secund , iar mai târziu ... cine stie ce va mai ?!
9
https://en.wikipedia.org/wiki/List_of_fastest_computers
iii
În perioada 2017-2020 cele mai puternice calculatoare din lume au fost: în noiembrie 2017 în
China, în noiembrie 2019 în SUA ³i ... în iunie 2020 în Japonia (Fugaku: 415 petaops, adic
15 10
415 10 operaµii pe secund , adic ... 415 milioane de ... miliarde de ... operaµii pe secund ).
11
O mic observaµie: în 2017 a fost prima ediµie a olimpiadei EJOI în Bulgaria ³i ... tot în
12
Bulgaria a fost ³i prima ediµie a olimpiadei IOI în 1989.
Dar ... prima ediµie a olimpiadei IMO (International Mathematical Olympiad) a fost în
13
România în 1959. Tot în România s-au µinut ediµiile din anii 1960, 1969, 1978, 1999 ³i 2018.
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!). Totu³i, vor prezentate ³i Rezolv ri
detaliate ale problemelor de liceu (pe care le-am considerat în mod subiectiv!) utile.
Î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) nu au nevoie de ajutorul meu! Se descurc singuri! La
Indicaµii de rezolvare voi prezenta numai ... numele algoritmilor clasici folosiµi în rezolvare.
10
https://www.top500.org/lists/top500/
11
https://ejoi.org/about/
12
https://stats.ioinformatics.org/olympiads/
13
https://en.wikipedia.org/wiki/International_Mathematical_Olympiad
14
https://www.etsy.com/listing/604809336/john-wayne-quotes-i-am-only-responsible
"Acknowledgements"
15
"I want to thank God most of all because without God I wouldn't be able to do any of this."
Adrian R.
15
I.d.k.: "I don't know who the author is."
v
Despre autor16
nume: R bâea Aurel-Adrian, 18.03.1953 - ...
adresa: Str. Valea Ghinzii nr. 21 B, Bistriµa, România
telefon: +40 728 18 03 53 +40 363 10 25 10
email: adrian1803@gmail.com
Lector universitar - Universitatea Tehnic din Cluj Napoca - Centrul
Universitar Nord din Baia Mare, Facultatea de tiinµe, Str. Victoriei,
nr. 76, Baia Mare, România, (pensionat: 01.10.2018)
http://www.stiinte.utcluj.ro/
Discipline predate (1992-2018):
Algoritmi ³i structuri de date, Algoritmi în teoria opµiunilor nanciare, Bazele matematice
ale calculatoarelor, Bazele tehnologiei informaµiei, Birotic , Capitole speciale de inteligenµ
articial , Capitole speciale de teoria algoritmilor, Calcul paralel, Informatic economic ,
Instruire asistat de calculator, Limbaje de programare; Programare orientat pe obiecte,
Programare procedural , Structuri de date,
16
https://stiinte.utcluj.ro/files/cv/CV%20Rabaea_Adrian.pdf
17
http://opac.biblioteca.ase.ro/opac/bibliographic_view/149021
18
http://www.ionivan.ro/2015-PERSONALITATI/Dodescu.htm
19
https://sites.google.com/site/ciprianatudor/Home/professor-constantin-tudor
20
https://ro.wikipedia.org/wiki/Ion_V%C4%83duva
vi
Cuprins
Prefaµ iii
Cuprins vii
Lista gurilor xiii
Lista tabelelor xiv
Lista programelor xv
1 IOI 2020 1
1.1 plants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1.1 Indicaµii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1.2 Coduri surs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.1.3 *Rezolvare detaliat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
1.2 supertrees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
1.2.1 Indicaµii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
1.2.2 Coduri surs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
1.2.3 *Rezolvare detaliat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
1.3 tickets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
1.3.1 Indicaµii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
1.3.2 Coduri surs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
1.3.3 *Rezolvare detaliat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
1.4 biscuits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
1.4.1 Indicaµii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
1.4.2 Coduri surs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
1.4.3 *Rezolvare detaliat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
1.5 mushrooms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
1.5.1 Indicaµii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
1.5.2 Coduri surs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
1.5.3 *Rezolvare detaliat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
1.6 stations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
1.6.1 Indicaµii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
1.6.2 Coduri surs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
1.6.3 *Rezolvare detaliat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
vii
2.4.1 Indicaµii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
2.4.2 Coduri surs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
2.4.3 *Rezolvare detaliat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
2.5 Vision Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
2.5.1 Indicaµii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218
2.5.2 Coduri surs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
2.5.3 *Rezolvare detaliat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
2.6 Sky Walking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
2.6.1 Indicaµii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
2.6.2 Coduri surs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
2.6.3 *Rezolvare detaliat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
Glosar 1183
Bibliograe 1186
Lista autorilor 1189
Lista gurilor
2.1 Shoes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
2.2 Split1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
2.3 split2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
2.4 rectangular . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
2.5 Line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
2.6 vision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
2.7 walk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
xiii
Lista tabelelor
3.1 Combo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255
3.2 highway . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341
xiv
Lista programelor
1.1.1 graderPlants-sandbox.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.1.2 checkerPlants.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.1.3 plants_300416.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.1.4 plants_301340.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.1.5 plants_304504.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.1.6 plants_308350.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.2.1 graderSupertrees-sandbox.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
1.2.2 checkerSupertrees.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
1.2.3 supertrees_300160.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
1.2.4 supertrees_300292.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
1.2.5 supertrees_300293.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
1.2.6 supertrees_300296.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
1.2.7 supertrees_300447.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
1.2.8 supertrees_300489.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
1.2.9 supertrees_300657.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
1.2.10 supertrees_300806.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
1.3.1 graderTickets-sandbox.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
1.3.2 checkerTickets.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
1.3.3 tickets_300231.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
1.3.4 tickets_300591.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
1.3.5 tickets_300700.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
1.3.6 tickets_300781.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
1.3.7 tickets_300782.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
1.4.1 graderBiscuits-sandbox.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
1.4.2 checkerBiscuits.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
1.4.3 biscuits_305541.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
1.4.4 biscuits_305864.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
1.4.5 biscuits_306418.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
1.4.6 biscuits_306482.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
1.5.1 mushrooms_Model.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
1.5.2 mushrooms_303767.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
1.5.3 mushrooms_306077.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
1.5.4 mushrooms_938329.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
1.6.1 checkerStations.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
1.6.2 stations_304908.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
1.6.3 stations_304916.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
1.6.4 stations_304990.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
1.6.5 stations_306236.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
1.6.6 stations_306242.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
1.6.7 stations_306508.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
1.6.8 stations_306854.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
1.6.9 stations_308162.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
2.1.1 compile_cpp.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
2.1.2 shoes.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
2.1.3 shoes.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
2.1.4 grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
2.1.5 shoes-model.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
2.1.6 shoes-model+grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
2.1.7 shoes 143076+grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
xv
2.1.8 shoes 143080+grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
2.1.9 shoes-ds_ok+grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
2.1.10 shoes-jonathanirvings+grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . 154
2.1.11 shoes-kuzey_ok+grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
2.2.1 compile_cpp.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
2.2.2 split.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
2.2.3 split.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
2.2.4 grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
2.2.5 split-model.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
2.2.6 split-kostka-full+grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
2.2.7 split 144514+grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
2.2.8 split_koosaga+grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
2.2.9 split-mahdi+grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
2.2.10 split-maroon-accepted+grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . 177
2.3.1 compile_cpp.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
2.3.2 rect.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
2.3.3 rect.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
2.3.4 grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
2.3.5 rect-model.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
2.3.6 rectangle-mruxim-n2lg+grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . 187
2.3.7 rectangle 147888+grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
2.3.8 rectangle145193+grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
2.3.9 rectangle-peyman-n2lg-opt+grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . 198
2.4.1 compile_cpp.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
2.4.2 line.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
2.4.3 line.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
2.4.4 grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
2.4.5 line-model.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
2.4.6 sol-ge-most-optimal+grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
2.5.1 compile_cpp.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
2.5.2 vision.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
2.5.3 vision.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
2.5.4 grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
2.5.5 vision-model.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
2.6.1 compile_cpp.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
2.6.2 walk.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
2.6.3 walk.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
2.6.4 grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227
2.6.5 walk-model.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227
2.6.6 akm-full+grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
2.6.7 maroon-full+grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
2.6.8 mohammad-full-walk+grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . 238
2.6.9 walk 143257 Benq+grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
2.6.10 walk 147051+grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
3.1.1 compile_cpp.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
3.1.2 combo.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
3.1.3 combo.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
3.1.4 grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
3.1.5 combo-model.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258
3.1.6 combo_75294.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260
3.1.7 combo_75871.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
3.1.8 combo_76356.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263
3.1.9 combo_77113.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265
3.1.10 combo_koosaga.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267
3.2.1 compile_cpp.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272
3.2.2 seat.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272
3.2.3 seat.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272
3.2.4 grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272
3.2.5 seat-model.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
3.2.6 seats_75159.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276
3.2.7 seats_75485.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
3.2.8 seats_76357.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282
3.2.9 seats_80434.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
3.2.10 seats_81209.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289
3.3.1 compile_cpp.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
3.3.2 werewolf.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
3.3.3 werewolf.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
3.3.4 grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
3.3.5 werewolf-model.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296
3.3.6 werewolf_75105.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298
3.3.7 werewolf_75296.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302
3.3.8 werewolf_75793.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305
3.3.9 werewolf_81140.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308
3.3.10 werewolf_85439.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311
3.4.1 compile_cpp.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320
3.4.2 dool.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321
3.4.3 dool.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321
3.4.4 grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321
3.4.5 doll_75123.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323
3.4.6 dool_75619.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327
3.4.7 dool_76623.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331
3.4.8 dool_78782.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
3.5.1 compile_cpp.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344
3.5.2 highway.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344
3.5.3 highway.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344
3.5.4 grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344
3.5.5 highway_74962.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346
3.5.6 highway_77105.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351
3.5.7 highway_78948.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355
3.6.1 compile_cpp.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363
3.6.2 meetings.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363
3.6.3 meetings.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363
3.6.4 grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363
3.6.5 meetings-model.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364
3.6.6 meetings_76204.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367
3.6.7 meetings_120908.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 371
3.6.8 meetings_159115.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 375
4.1.1 nowruz.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383
4.1.2 checker.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387
4.1.3 addleaves.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 389
4.1.4 addleaves_once.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391
4.1.5 addleaves_rand.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393
4.1.6 dfs.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395
4.1.7 haircomb.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 398
4.1.8 nowruz1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399
4.2.1 wiring.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403
4.2.2 wiring+grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405
4.2.3 wiring-haas-ac.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407
4.2.4 wiring-haas-ac-ternary.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408
4.2.5 wiring-mahdi-ac.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
4.2.6 wiring-malek-ac.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412
4.2.7 wiring-saeed-ac.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414
4.2.8 wiring-197505.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415
4.2.9 wiring-200512.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417
4.2.10 wiring-206573.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 418
4.2.11 wiring-216947.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420
4.2.12 wiring-221801.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422
4.2.13 wiring-227702.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424
4.2.14 wiring-227979.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426
4.3.1 train.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 430
4.3.2 train+grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 431
4.3.3 checkerModicat.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433
4.3.4 train-malek-ac.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 434
4.3.5 train-saeed-ac.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436
4.3.6 train-134142.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 438
4.3.7 train-146520.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441
4.3.8 train-160375.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442
4.3.9 train-163181.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 445
4.3.10 train-201183.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448
4.3.11 train-221800.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451
4.3.12 train-222137.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454
4.4.1 prize.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 460
4.4.2 prize+graderpublic.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 462
4.4.3 prize-169927.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 464
4.4.4 prize-187329.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 467
4.4.5 prize-206577.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 469
4.4.6 prize-208873.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 472
4.4.7 prize-221802.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 475
4.4.8 prize-229052.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 477
4.4.9 prize-232826.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 480
4.5.1 simurgh.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 486
4.5.2 simurgh-33904.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 491
4.5.3 simurgh-70374.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 496
4.5.4 simurgh-70729.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 500
4.5.5 simurgh-136567.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 505
4.5.6 simurgh-137723.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 509
4.6.1 books+graderpublic.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 519
4.6.2 books-42759.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 522
4.6.3 books-51837.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 524
4.6.4 books-94567.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 526
4.6.5 books-122101.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 528
4.6.6 books-138862.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 530
4.6.7 books-152524.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 531
4.6.8 books-206638.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 533
5.1.1 molecules_sk.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 539
5.1.2 molecules_sk_greedy_1_n.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . 541
5.1.3 molecules_sk_greedy_2_n.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . 542
5.1.4 molecules_sk_greedy_3_ok.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . 543
5.1.5 molecules-20751.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 545
5.1.6 molecules-72936.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 546
5.1.7 molecules-93472.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 548
5.1.8 molecules-114550.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 549
5.1.9 molecules-159299.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 550
5.2.1 railroad_mp_nlogn.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 554
5.2.2 railroad-103076.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 556
5.2.3 railroad-117891.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 558
5.2.4 railroad-135900.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 560
5.2.5 railroad-223610.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 561
5.2.6 railroad-233098.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 564
5.3.1 shortcut_c.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 570
5.3.2 sol_ge_nlogd.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 572
5.3.3 sol_ge_nlogd_fastio.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 575
5.3.4 sol_nk_nlogd.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 578
5.3.5 shortcut-24626.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 581
5.3.6 shortcut-33932.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 583
5.3.7 shortcut-94572.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 585
5.3.8 shortcut-97033.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 587
5.3.9 shortcut-99074.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 590
5.3.10 shortcut-99075.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 592
5.3.11 shortcut-113364.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 595
5.3.12 shortcut-114144.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 596
5.3.13 shortcut-142952.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 598
5.3.14 shortcut-162764.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 600
5.3.15 shortcut-207049.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 603
5.3.16 shortcut-225819.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 605
5.4.1 paint_c.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 612
5.4.2 paint_iz.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 615
5.4.3 solve-correct-lc.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 618
5.4.4 checkerPaintModicat.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 620
5.4.5 paint-65961.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 621
5.4.6 paint-66328.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 623
5.4.7 paint-97040.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 625
5.4.8 paint-105782.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 626
5.4.9 paint-107399.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 628
5.4.10 paint-108251.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 630
5.4.11 paint-112136.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 632
5.4.12 paint-130510.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 634
5.4.13 paint-180292.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 636
5.4.14 paint-204502.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 638
5.5.1 checkerMessyModicat.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 643
5.5.2 messy_cpp_ok.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 644
5.5.3 messy_iz.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 647
5.5.4 messy_tourist.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 650
5.5.5 messy-21910.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 654
5.5.6 messy-23726.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 658
5.5.7 messy-23992.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 661
5.5.8 messy-59231.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 664
5.5.9 messy-66964.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 667
5.5.10 messy-67587.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 670
5.5.11 messy-70792.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 674
5.5.12 messy-71456.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 677
5.5.13 messy-102062.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 680
5.6.1 checkerAliens.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 688
5.6.2 alien-bsearch.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 689
5.6.3 aliens_ma_nlogm.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 693
5.6.4 aliens_ma_nlogm_double.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . 695
5.6.5 alien-32012.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 697
5.6.6 alien-43618.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 700
5.6.7 alien-45993.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 702
5.6.8 alien-70398.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 704
5.6.9 alien-94585.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 706
5.6.10 alien-96357.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 708
5.6.11 alien-97219.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 710
5.6.12 alien-121473.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 712
5.6.13 alien-166476.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 715
5.6.14 alien-171563.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 717
5.6.15 alien-172712.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 720
5.6.16 alien-173410.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 722
5.6.17 alien-224940.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 725
5.6.18 alien-225911.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 727
5.6.19 alien-228077.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 729
6.1.1 boxes-16533.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 736
6.1.2 boxes-64042.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 737
6.1.3 boxes-70567.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 741
6.1.4 checkerBoxes.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 742
6.2.1 graderlib.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 746
6.2.2 scales-45773.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 748
6.2.3 scales-115418.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 750
6.2.4 scales-122639.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 753
6.2.5 checkerScales.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 756
6.3.1 teams-17286.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 760
6.3.2 teams-69885.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 763
6.3.3 teams-172439.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 766
6.3.4 checkerTeams.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 769
6.4.1 horses-91995.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 773
6.4.2 horses-102703.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 775
6.4.3 horses-202434.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 778
6.4.4 checkerHorses.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 781
6.5.1 sorting-70140.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 785
6.5.2 sorting-114135.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 788
6.5.3 sorting-129522.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 791
6.5.4 sorting-155927.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 793
6.5.5 sorting-225877.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 795
6.5.6 sorting-233228.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 797
6.6.1 graderlib.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 804
6.6.2 towns-127541.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 804
6.6.3 towns-134867.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 807
6.6.4 towns-151462.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 809
6.6.5 checkerTowns.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 811
7.1.1 game-92195.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 816
7.1.2 game-117330.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 817
7.1.3 game-231330.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 819
7.1.4 game_n2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 820
7.1.5 checkerGame.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 821
7.2.1 rail-117000.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 824
7.2.2 rail-121219.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 828
7.2.3 rail-125767.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 832
7.2.4 rail-139096.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 835
7.2.5 rail-173712.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 839
7.3.1 wall-39307.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 846
7.3.2 wall-93939.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 847
7.3.3 wall-173006.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 849
7.3.4 wall-232336.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 851
7.3.5 checkerWall.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 853
7.4.1 friend-16524.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 858
7.4.2 friend-115760.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 860
7.4.3 friend-119597.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 861
7.4.4 checkerFriend.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 862
7.5.1 gondola-7306.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 867
7.5.2 gondola-93790map.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 869
7.5.3 gondola-102776.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 871
7.5.4 gondola-153281.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 874
7.5.5 checkerGondola.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 876
7.6.1 holiday-120785.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 880
7.6.2 holiday-134641.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 882
7.6.3 holiday-211797.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 884
7.6.4 holiday-229391.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 886
7.6.5 checkerHoliday.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 889
8.2.1 cave-1749.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 897
8.2.2 cave-16655.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 899
8.2.3 cave-170339.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 901
8.2.4 cave-231414.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 904
8.2.5 checkerCave.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 907
8.3.1 dreaming-3168.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 910
8.3.2 dreaming-16636.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 913
8.3.3 dreaming-81476.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 915
8.3.4 dreaming-172308.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 917
8.3.5 dreaming-198762.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 919
8.3.6 checkerDreaming.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 920
8.4.1 game-220385.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 925
8.4.2 game-224978.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 929
8.4.3 game-225963.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 932
8.4.4 checkerGame.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 935
8.5.1 robot-7026.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 939
8.5.2 robot-7037.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 942
8.5.3 robot-17227.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 944
8.5.4 robot-96364.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 947
8.5.5 checkerRobot.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 950
8.6.1 wombats-108194.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 957
8.6.2 wombats-108196.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 959
8.6.3 wombats-118871.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 961
8.6.4 checkerWombats.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 963
9.1.1 odometer.py . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 968
9.2.1 rings.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 972
9.2.2 rings-13540.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 976
9.2.3 rings-49004.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 979
9.2.4 rings-62499.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 981
9.2.5 rings-223749.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 984
9.2.6 rings-233348.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 987
9.2.7 checkerRings.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 990
9.3.1 scrivener.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 993
9.3.2 scrivener-7279.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 995
9.3.3 scrivener-18725.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 997
9.3.4 scrivener-230126.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 999
9.3.5 checkerScrivener.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1001
9.4.1 city.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1004
9.4.2 city-16324.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1008
9.4.3 city-18847.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1010
9.4.4 city-32163.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1013
9.4.5 city-197022.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1015
9.4.6 checkerCity.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1018
9.5.1 supper.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1023
9.5.2 supper-231107.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1028
9.6.1 tournament.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1034
9.6.2 tournament-2193.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1038
9.6.3 tournament-4657.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1040
9.6.4 tournament-14774.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1042
9.6.5 checkerTournament.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1044
10.1.1 garden-49449.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1050
10.1.2 garden-49789.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1052
10.1.3 garden-116557.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1055
10.1.4 checkerGarden.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1058
10.2.1 race-28930.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1062
10.2.2 race-112526.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1064
10.2.3 race-216556.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1066
10.2.4 checkerRace.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1068
10.3.1 racehub-7321.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1072
10.3.2 racehub-95096.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1073
10.3.3 racehub-113697.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1074
10.3.4 racehub-116283.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1076
10.3.5 checkerRaceHub.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1077
10.4.1 crocodile-10431.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1081
10.4.2 crocodile-16656.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1083
10.4.3 crocodile-133704.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1085
10.4.4 crocodile-228833.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1087
10.4.5 checkerCrocodile.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1088
10.5.1 elephants-115857.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1093
10.5.2 elephants-192442.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1095
10.5.3 elephants-207733.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1098
10.5.4 checkerElephants.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1101
10.6.1 parrot-224033.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1107
10.6.2 parrots-235627.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1112
11.1.1 cluedosol.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1119
11.1.2 cluedosol.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1120
11.1.3 cluedo-218031.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1120
11.1.4 cluedo-220599.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1121
11.1.5 cluedo-229322.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1122
11.2.1 coldersol1.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1127
11.2.2 coldersol2.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1127
11.2.3 hottercolder.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1128
11.2.4 hottercolder-173047.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1131
11.2.5 hottercolder-201977.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1133
11.3.1 rectanglesol.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1139
11.3.2 quality-208958.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1140
11.3.3 quality-234933.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1142
11.3.4 checkerQuality.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1144
11.4.1 lang-8124.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1146
11.4.2 lang-12891.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1148
11.4.3 lang-155338.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1150
11.4.4 lang-235517.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1152
11.5.1 memory.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1156
11.5.2 memory.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1156
11.5.3 memory-206951.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1157
11.5.4 memory-217254.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1158
11.5.5 memory-232610.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1159
11.6.1 quality-229321.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1163
11.6.2 quality-232654.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1164
11.6.3 quality-236364.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1165
11.6.4 checkerQuality.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1167
11.8.1 saveit-231998.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1173
11.8.2 saveit-224546.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1176
Capitolul 1
IOI 202021
1.1 plants
Problema 1 - Comparing Plants 100 de puncte
Author: Jo Sunghyeon
Botanistul Hazel a vizitat o expoziµie special în Gr dina Botanic din Singapore. În aceast
expoziµie, n plante cu în lµimi distincte sunt plasate într-un cerc. Aceste plante sunt etichetate
de la 0 la n 1 în ordinea acelor de ceasornic, cu planta n 1 lâng planta 0.
Pentru ecare plant i (0 & i & n 1), Hazel a comparat planta i cu ecare dintre urm toarele
k 1 plante în ordine în sensul acelor de ceasornic ³i a notat num rul ri indicând câte dintre
aceste k 1 plante sunt mai înalte decât planta i. Astfel, ecare valoare ri depinde de în lµimile
relative a k plante consecutive.
De exemplu, s presupunem c n 5, k 3 ³i i 3. Urm toarele k 1 2 plante în ordinea
acelor de ceasornic dup planta i 3 vor plantele 4 ³i 0. Dac planta 4 este mai înalt decât
planta 3 ³i planta 0 este mai scund decât planta 3, atunci Hazel notateaz r3 1.
Puteµi presupune c Hazel a înregistrat corect valorile ri. Astfel, exist cel puµin o congu-
raµie de în lµimi distincte ale plantelor în concordanµ cu aceste valori.
Vi se cere s comparaµi în lµimile a q perechi de plante. Din p cate, nu aveµi acces la expoziµie.
Singura dvs. surs de informaµii este caietul lui Hazel ce conµine valoarea lui k ³i secvenµa valorilor
r0, ..., rn 1.
Pentru ecare pereche de plante diferite x ³i y care trebuie comparate, determinaµi în care
dintre urm toarele trei situaµii ne încadr m:
Planta x este cu siguranµ mai înalt decât planta y : în orice conguraµie de în lµimi distincte
h0, ..., hn 1 în concordanµ cu tabloul r avem hx % hy .
Planta x este cu siguranµ mai scund decât planta y : în orice conguraµie de în lµimi
distincte h0, ..., hn 1 în concordanµ cu tabloul r avem hx % hy .
Comparaµia este neconcludent : niciunul dintre cele dou cazuri anterioare nu se aplic .
Detalii de implementare
Trebuie s implementaµi urm toarele funcµii:
k : num rul de plante consecutive ale c ror în lµimi determin valorile individuale ale lui
ri.
21
aur: Alexandru Luchianov, Liceul Internaµional de Informatic din Bucure³ti,
. argint: Maria Alexa Tudose, C. N. I. L. Caragiale din Ploie³ti,
. argint: Alexandra Maria Udri³toiu, C. N. Fraµii Buze³ti din Craiova,
. bronz: George Alexandru Râpeanu, C. N. Emil Racoviµ din Cluj-Napoca
1
CAPITOLUL 1. IOI 2020 2
Exemple
Exemplul 1 Consider m apelul:
init(3, [0, 1, 1, 2])
Restricµii
a 2 & k & n & 200 000
a 1 & q & 2000 000
a 0 & r i & k 1 (oricare ar 0 & i & n 1)
a 0 & x $ y & n1
a Exist una sau mai multe conguraµii de în lµimi distincte ale plantelor în concordanµ
cu tabloul r.
Subtaskuri
1. (5 puncte) k 2
2. (14 puncte) n & 5000, 2 k % n
3. (13 puncte) 2 k % n
4. (17 puncte) R spunsul corect pentru ecare apel compare_plants este 1 sau -1.
(11 puncte) n & 300, q &
n n1
5. 2
6. (15 puncte) x 0 pentru toate apelurile compare_plants.
7. (25 de puncte) Fara restricµii suplimentare.
CAPITOLUL 1. IOI 2020 3
Sample grader
Graderul cite³te în formatul urm tor:
linia 1: n k q
linia 2: r0 r1 ... rn 1
linia 3 i (0 & i & q 1): x y pentru al i-lea apel al funcµiei compare_plants
Graderul tip re³te r spunsul t u în formatul urm tor:
linia 1 i (0 & i & q 1): x valoarea returnat de al i-lea apel al funcµiei compare_plants.
For simplicity of describing the solutions, all indices of the array will be taken modulo n.
Subtask 1
We are given the height comparisons of each pair of adjacent plants. We can conclude that plant
x is taller than plant y if either of the following holds:
a r x rx 1 ... ry 1 0
a r y 1 ... rn 2 rn 1 1 and r0 r1 ... rx 1 1
The condition for returning -1 is similar.
If none of the conditions hold, return 0.
Implementing this naively requires O nq time. We can speed this up by using a static prex
sum array.
Subtask 2
The overall idea is to generate a possible conguration of heights.
First observe that the tallest plant x must satisfy rx 0. This suggests the following
algorithm:
Repeat the following for n times:
1. Look for some index x such that rx 0
2. Decrement rx k 1, rx k 2, ..., rx 1, rx by 1
Consider the input n 3, k 2, r 0, 1, 0. The tallest plant must be 2. However, we also
have rx 0. We therefore need to replace rule (1) with the following:
a Look for some index x such that rx 0 and rx k 1, rx k 2, ..., rx 1 j 0. (*)
The index x satisfying the above condition is always unique (and therefore the nal congu-
ration of heights is also unique). The order in which these x are chosen will give rise to a possible
conguration of heights, in which we can answer all the queries by simply comparing the heights.
2
Complexity O n .
Subtask 3
Same as above; except that we need to use a segment tree with lazy propagation to speed up the
algorithm. However, it can be tricky to implement (*).
To do this, we choose a value t such that rt 0. If there are multiple of them, choose the
smallest. We can do a range minimum query to check if any of rt k 1, ..., rt 1 is zero. If
none of them are zero, we choose x t.
If not, we let x be the smallest index among t k 1, ..., t 1 such that rx 0.
Other than the potentially more tedious implementation of (*), the rest of the algorithm
remains the same. Complexity O n log n.
CAPITOLUL 1. IOI 2020 4
Subtask 4
The implementation of (*) becomes more problematic here. To illustrate, suppose that k 2 and
r0 r1 ... rn 2 0, rn 1 1.
If we choose the value t n 2, we realise that rn 3 0. However, we run into further
problems because rn 4 is also zero.
As such, we need to recursively search for the correct index. Complexity O n log n.
extract(x):
while there is a y in {x-k+1, x-k+2, ..., x-1} such that r[y]==0:
extract(y)
end
decrement r[x-k+1], r[x-k+2], ..., r[x] by 1
The ordering of the heights is then given by the order in which the procedure returns (rather
than the order the of being called). The queries can still be answered by a direct comparison of
the heights.
Subtask 5
We rst generate a possible conguration of heights h0, 1, ..., n 1 using the techniques from the
previous subtasks.
Dene d x, y min ¶x y ¶, ¶x n y ¶, ¶y n x¶ to be the distance between plants x and
y . Generate a directed graph with x y if and only if hx % hy and d x, y $ k .
Lemma:
a The above graph generated does not depend on the choice of h . In other words, any two
height arrays h1 and h2 consistent with r will generate the same directed graph.
Proof:
a Let G be any directed graph consistent with the input r (that is, for each i, there are
exactly ri values of j among i 1, i 2, ..., i k 1 such that j i).
a We rst observe that any valid conguration h corresponds to a run of the algorithm (*).
a It is therefore sucient to show that any run of the algorithm (*) generates a topological sort
of this graph G.
22
a The proof is similar to Kahn's algorithm . When plant is removed by the algorithm (*), the
conditions for removing guarantee that must have zero in-degree.
a Since we only remove nodes with zero in-degree, the order generated must correspond to a
valid topological sort of G.
To check if plant x is taller than plant y , we check if there exists a (directed) path from x to y .
To do so, we can compute the transitive closure using Flyod-Warshall] and pre-compute the
3
answers to the entire space of queries. Complexity O n .
Alternative solution to subtask 5 We follow the idea of (*). We look for some z such that
rz 0 and rz k 1, rz k 2, ..., rz 1 j 0, but now including an additional constraint
that z j x. We stop when x is the only plant we can remove.
There exists a conguration of heights such that plant y is taller than plant x if and only if
the above algorithm removes plant x.
2 4
Take note that doing so naively would require computation O nq O n time, if we do not
use a segment tree.
However, it is easy to speed this up to O n . For each plant 0 & x & n 1, we pre-compute
3
in advance all y such that y can possibly be taller than x, storing them in a n n table.
Subtask 6
Same idea as subtask 5. However, we are unable to generate the entire graph as there can be up
to O nk edges.
22
https://www.geeksforgeeks.org/topological-sorting-indegree-based-solution/
CAPITOLUL 1. IOI 2020 5
For each plant x, dene the 'left edge' and 'right edge' as follows:
a lef t x the tallest plant shorter than x among x k 1, ..., x 1 or -1 if it does not exist
a lef t x the tallest plant shorter than x among x 1, ..., x k 1 or -1 if it does not exist
We now generate a graph with edges x lef t x and x right x for each x. To check if
plant is taller than plant x, we check if there exists a (directed) path from x to y .
Since we only need to compare against plant 0, we can use single-source BFS or DFS to nd
all vertices reachable from 0.
Complexity O n log n (the queries are answered in O 1 time, however we need O n log n to
generate the array h , each value of lef t x and right x requires O log n to compute.
We may also use the idea to the alternative solution of subtask 5. After nding all the plants
that can be taller than plant 0, we can invert the ranks (i.e. ri replace with k 1 ri for each
i) to check if a plant can shorter than plant 0.
Subtask 7
For each query x, y , let z be the rst value among lef t x, lef t lef t x, lef t lef t lef t x
... such that y is between z and lef t z .
If hz % hy , we can then conclude that x is taller than y .
We do so similarly for the right edges.
To speed up this computation, we use power-of-2 tables:
30 int p_lt[n_max];
31 int p_rg[n_max];
32 int stash[n_max]; // a manual queue
33 int tallest[n_max];
34 int shortest[n_max];
35
36 struct segtree
37 {
38 int node = 1;
39 int lazy = 0;
40 segtree(){}
41 void build(vector<int> &v)
42 {
43 assert(v.size()<(1<<n_bits));
44 for(int i=0; i<(1<<n_bits); i++)
45 {
46 arr[i+(1<<n_bits)] = (i<(int)v.size() ? v[i] : inf);
47 }
48 for(int i=(1<<n_bits)-1; i>=1; i--)
49 {
50 arr[i] = min(arr[2*i], arr[2*i+1]);
51 }
52 for(int i=0; i<(1<<(n_bits+1)); i++)
53 {
54 lazyadd[i] = 0;
55 }
56 }
57
58 void prefix_update(int x, int change)
59 {
60 if(x==-1) return;
61 x += (1<<n_bits);
62 lazyadd[x] += change;
63 for(int i=0; i<n_bits; i++)
64 {
65 if(x&1)
66 {
67 lazyadd[x-1] += change;
68 }
69 arr[x/2] = min(arr[x]+lazyadd[x], arr[x^1]+lazyadd[x^1]);
70 x=x/2;
71 }
72 }
73
74 void decr(int left, int right)
75 {
76 prefix_update(left-1, 1);
77 prefix_update(right,-1);
78 }
79
80 int find_and_remove_zero()
81 {
82 node = 1;
83 lazy = 0;
84 for(int i=0; i<n_bits; i++)
85 {
86 lazy += lazyadd[node];
87 node *= 2;
88 if(lazy + lazyadd[node] + arr[node]) node++;
89 }
90 int ans = node - (1<<n_bits);
91 lazyadd[node] = 1e9;
92 for(int i=0; i<n_bits; i++)
93 {
94 arr[node/2] = min(arr[node]+lazyadd[node],
95 arr[node^1]+lazyadd[node^1]);
96 node = node/2;
97 }
98 return ans;
99 }
100 };
101
102 void lexi_smallest(int k, vector<int> &r, int* ptr, int* ord)
103 {
104 segtree s;
105 s.build(r);
CAPITOLUL 1. IOI 2020 7
28 //readBothGraderResults();
29
30 compareRemainingLines();
31 }
32 /*
33 argc = 4
34 checker
35 ../tests/7-15.in
36 ../tests/7-15.out
37 plants.out
38 ----------------------
39 1
40 Correct
41
42 Process returned 0 (0x0) execution time : 0.641 s
43 Press any key to continue.
44 */
56 {
57 seg[a].val = seg[2*a].val;
58 seg[a].ind = seg[2*a].ind;
59 }
60 else
61 {
62 seg[a].val = seg[2*a+1].val;
63 seg[a].ind = seg[2*a+1].ind;
64 }
65 seg[a].val += seg[a].lazy;
66 seg[a].last_taken = max(seg[2*a].last_taken,
67 seg[2*a+1].last_taken);
68 };
69
70 for (int i = 0; i < N; i++)
71 {
72 seg[N+i] = seg_node{R[i], i, 0, -1};
73 }
74 for (int a = N-1; a; a--) update_node(a);
75
76 auto downdate_all = [&](int n)
77 {
78 n >>= __builtin_ctz(n); n >>= 1;
79 if (!n) return;
80 for (int l = 31 - __builtin_clz(n); l >= 0; l--)
81 {
82 int a = n >> l;
83 assert(a < N);
84 seg[2*a].val += seg[a].lazy;
85 seg[2*a].lazy += seg[a].lazy;
86 seg[2*a+1].val += seg[a].lazy;
87 seg[2*a+1].lazy += seg[a].lazy;
88 seg[a].lazy = 0;
89 }
90 };
91
92 std::vector<int> toposort; toposort.reserve(N);
93 std::vector<int> stk; stk.reserve(N);
94 std::vector<int> prev_bigger(N);
95 std::vector<int> next_bigger(N);
96 while (int(toposort.size()) < N)
97 {
98 if (stk.empty())
99 {
100 assert(seg[1].val == 0);
101 stk.push_back(seg[1].ind);
102 }
103
104 int cur = stk.back();
105 //std::cerr << "trying " << cur << ’\n’;
106
107 int prev_taken = -1;
108 int lo = cur-(K-1), hi = cur;
109 if (lo < 0)
110 {
111 lo += 2 * N, hi = 2 * (N + hi);
112 }
113 else
114 {
115 lo += N, hi += N;
116 }
117
118 downdate_all(lo);
119 downdate_all(hi);
120
121 int zero_ind = -1;
122 for (int a = lo, b = hi; a < b; a >>= 1, b >>= 1)
123 {
124 if (a & 1)
125 {
126 if (seg[a].val == 0)
127 {
128 zero_ind = seg[a].ind;
129 goto found_zero;
130 }
131 prev_taken = max(prev_taken, seg[a].last_taken);
CAPITOLUL 1. IOI 2020 11
132 a++;
133 }
134
135 if (b & 1)
136 {
137 --b;
138 if (seg[b].val == 0)
139 {
140 zero_ind = seg[b].ind;
141 goto found_zero;
142 }
143 prev_taken = max(prev_taken, seg[b].last_taken);
144 }
145 }
146
147 goto not_found_zero;
148
149 found_zero:
150 {
151 //std::cerr << "bad: " << zero_ind << ’\n’;
152 stk.push_back(zero_ind);
153 continue;
154 }
155
156 not_found_zero:;
157 int next_taken = -1;
158 {
159 int lo2 = cur+1, hi2 = cur+K;
160 assert(lo2 <= N);
161 lo2 += N;
162 if (hi2 > N)
163 {
164 hi2 = 2 * hi2;
165 }
166 else
167 {
168 hi2 += N;
169 }
170
171 for (int a = lo2, b = hi2; a < b; a >>= 1, b >>= 1)
172 {
173 if (a & 1)
174 {
175 next_taken = max(next_taken, seg[a].last_taken);
176 a++;
177 }
178
179 if (b & 1)
180 {
181 --b;
182 next_taken = max(next_taken, seg[b].last_taken);
183 }
184 }
185 }
186
187 assert(stk.back() == cur);
188 stk.pop_back();
189 int t = int(toposort.size());
190 toposort.push_back(cur);
191 prev_bigger[cur]=(prev_taken==-1) ? -1 : toposort[prev_taken];
192 next_bigger[cur]=(next_taken==-1) ? -1 : toposort[next_taken];
193
194 //std::cerr << "take " << cur << ’ ’ << \
195 prev_bigger[cur] << ’ ’ << next_bigger[cur] << ’\n’;
196
197 seg[N+cur].last_taken = t;
198 seg[N+cur].val += K; // should never be bad
199 for (int a = lo, b = hi; a < b; a >>= 1, b >>= 1)
200 {
201 if (a & 1)
202 {
203 seg[a].lazy--;
204 seg[a].val--;
205 a++;
206 }
207
CAPITOLUL 1. IOI 2020 12
208 if (b & 1)
209 {
210 --b;
211 seg[b].lazy--;
212 seg[b].val--;
213 }
214 }
215
216 for (int a = (N+cur) >> 1; a; a >>= 1) update_node(a);
217 for (int a = lo >> __builtin_ctz(lo) >> 1;
218 a;
219 a >>= 1) update_node(a);
220 }
221
222 {
223 std::vector<int> pred(2*N+1, -1);
224 {
225 int cur = 2*N;
226 for (int a : toposort)
227 {
228 if (a > N-K)
229 {
230 pred[cur] = N+a;
231 cur = N+a;
232 }
233 }
234 }
235
236 for (int i = 2*N-K; i >= 0; i--)
237 {
238 assert(i + K <= 2 * N);
239 int j = next_bigger[i >= N ? i-N : i];
240 if (j == -1)
241 {
242 j = 2 * N;
243 }
244 else
245 {
246 if (j < i) j += N;
247 assert(i < j && j < i + K);
248 }
249 pred[i] = pred[j];
250 pred[j] = i;
251 }
252
253 for (int cur = pred[2*N], idx = 2*N-1;
254 idx >= 0;
255 cur = pred[cur], idx--)
256 {
257 if (cur >= N)
258 {
259 v[cur - N].l_to_r_2 = idx;
260 }
261 else
262 {
263 v[cur].l_to_r = idx;
264 }
265 }
266 }
267
268 for (int i = 0; i < N; i++)
269 {
270 //std::cerr << v[i].l_to_r << ’ ’ << v[i].l_to_r_2 << ’\n’;
271 assert(v[i].l_to_r > v[i].l_to_r_2);
272 }
273
274 {
275 std::vector<int> pred(2*N+1, -1);
276 {
277 int cur = 2 * N;
278 for (int a : toposort)
279 {
280 if (a < K)
281 {
282 pred[cur] = a;
283 cur = a;
CAPITOLUL 1. IOI 2020 13
284 }
285 }
286 }
287
288 for (int i = K; i < 2*N; i++)
289 {
290 int j = prev_bigger[i >= N ? i-N : i];
291 if (j == -1)
292 {
293 j = 2 * N;
294 }
295 else
296 {
297 if (j + N < i)
298 {
299 j += N;
300 }
301 assert(i - K < j && j < i);
302 }
303 pred[i] = pred[j];
304 pred[j] = i;
305 }
306
307 for (int cur = pred[2*N], idx = 2*N-1;
308 idx >= 0;
309 cur = pred[cur], idx--)
310 {
311 if (cur >= N)
312 {
313 v[cur - N].r_to_l_2 = idx;
314 }
315 else
316 {
317 v[cur].r_to_l = idx;
318 }
319 }
320 }
321
322 for (int i = 0; i < N; i++)
323 {
324 //std::cerr << v[i].r_to_l << ’ ’ << v[i].r_to_l_2 << ’\n’;
325 assert(v[i].r_to_l_2 > v[i].r_to_l);
326 }
327 }
328
329 public:
330 int compare_plants(int x, int y) const
331 {
332 if (x == y) return 0;
333 if (x > y)
334 {
335 return -compare_plants(y, x);
336 }
337 assert(x < y);
338 const auto& a = v[x];
339 const auto& b = v[y];
340 if (a.l_to_r < b.l_to_r)
341 {
342 return -1;
343 }
344 if (b.l_to_r < a.l_to_r_2)
345 {
346 return 1;
347 }
348 if (a.r_to_l_2 < b.r_to_l)
349 {
350 return -1;
351 }
352 if (b.r_to_l < a.r_to_l)
353 {
354 return 1;
355 }
356
357 return 0;
358 }
359 } SOLVER;
CAPITOLUL 1. IOI 2020 14
360
361 }
362
363 void init(int K, std::vector<int> R)
364 {
365 int N = int(R.size());
366 SOLVER = plants_solver(N, K, R);
367 }
368
369 int compare_plants(int x, int y)
370 {
371 return SOLVER.compare_plants(x, y);
372 }
373
374 // ---------------------------------------------------
375
376 int main()
377 {
378 std::clock_t c_start = std::clock();
379 auto t_start = std::chrono::high_resolution_clock::now();
380
381 auto t1 = clock();
382
383 std::freopen("../tests/7-15.in", "r", stdin) ;
384 std::freopen("plants.out", "w", stdout) ;
385
386 assert(scanf("%d%d%d", &n, &k, &q) == 3);
387
388 r.resize(n);
389 answer.resize(q);
390 for (int i = 0; i < n; i++)
391 {
392 int value;
393 assert(scanf("%d", &value) == 1);
394 r[i] = value;
395 }
396 x.resize(q);
397 y.resize(q);
398 for (int i = 0; i < q; i++)
399 {
400 assert(scanf("%d%d", &x[i], &y[i]) == 2);
401 }
402 fclose(stdin);
403
404 auto t2 = clock();
405
406 init(k, r);
407 for (int i = 0; i < q; i++)
408 {
409 answer[i] = compare_plants(x[i], y[i]);
410 }
411
412 auto t3 = clock();
413
414 for (int i = 0; i < q; i++)
415 {
416 printf("%d\n", answer[i]);
417 }
418
419 fclose(stdout);
420
421 auto t4 = clock();
422
423 std::clock_t c_end = std::clock();
424 auto t_end = std::chrono::high_resolution_clock::now();
425
426 // reset console output
427 freopen("CON", "w", stdout);
428
429 //std::cout <<result<<’\n’<<’\n’;
430 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
431 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
432 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
433
434 std::cout << std::fixed << std::setprecision(2)
435 << "\nCPU time used: "
CAPITOLUL 1. IOI 2020 15
55 if(node<(1<<n_bits))
56 {
57 lazyadd[2*node] += lazyadd[node];
58 lazyadd[2*node+1] += lazyadd[node];
59 }
60 lazyadd[node] = 0;
61 return arr[node];
62 }
63
64 void update(int node, int left, int right, int change)
65 {
66 if(right>=high(node) && left<=low(node))
67 {
68 lazyadd[node] += change;
69 }
70 else
71 if(right<low(node) || left>high(node))
72 {
73 return;
74 }
75 else
76 {
77 update(2*node, left, right, change);
78 update(2*node+1, left, right, change);
79 arr[node] = min(value(node*2), value(node*2+1));
80 }
81 }
82
83 void decr(int left, int right)
84 {
85 update(1, left, right, -1);
86 }
87
88 int find_zero(int node)
89 {
90 if(value(node)!=0)
91 {
92 return -1;
93 }
94 if(node >= (1<<n_bits))
95 {
96 return arr[node]==0 ? node-(1<<n_bits) : -1;
97 }
98 int x = find_zero(node*2);
99 if(x!=-1) return x;
100 return find_zero(node*2+1);
101 }
102 };
103
104 // gives you the lexi smallest ordering given the doubled array r
105 vector<int> lexi_smallest(int k, vector<int> r)
106 {
107 segtree s;
108 s.build(r);
109 vector<int> ret;
110 ret.resize(r.size());
111 queue<int> stash;
112
113 for(int i=0; i<(int)r.size(); i++)
114 {
115 int p = s.find_zero(1);
116 while(p==-1)
117 {
118 s.decr(stash.front(), 2*n_global-1);
119 p = s.find_zero(1);
120 stash.pop();
121 }
122 ret[p] = i;
123 s.update(1, p, p, 1e9);
124
125 s.decr(max(0, p-k+1), p);
126 if(p<k-1)
127 {
128 stash.push(p-k+1+2*n_global);
129 }
130 }
CAPITOLUL 1. IOI 2020 17
131
132 return ret;
133 }
134
135 void init(int k, std::vector<int> r)
136 {
137 n_global = r.size();
138 for(int i=0; i<n_global; i++)
139 {
140 r.push_back(r[i]);
141 }
142 tallest = lexi_smallest(k,r);
143 for(int &i: r) i = k-1-i;
144 shortest = lexi_smallest(k,r);
145 }
146
147 int compare_plants(int x, int y)
148 {
149 if(x>y) return -compare_plants(y,x);
150 if(tallest[x]>tallest[y] || shortest[y]>shortest[x+n_global]) return -1;
151 if(shortest[x]>shortest[y] || tallest[y]>tallest[x+n_global]) return 1;
152 return 0;
153 }
154
155 // ---------------------------------------------------
156
157 int main()
158 {
159 std::clock_t c_start = std::clock();
160 auto t_start = std::chrono::high_resolution_clock::now();
161
162 auto t1 = clock();
163
164 std::freopen("../tests/7-15.in", "r", stdin) ;
165 std::freopen("plants.out", "w", stdout) ;
166
167 assert(scanf("%d%d%d", &n, &k, &q) == 3);
168
169 r.resize(n);
170 answer.resize(q);
171 for (int i = 0; i < n; i++)
172 {
173 int value;
174 assert(scanf("%d", &value) == 1);
175 r[i] = value;
176 }
177 x.resize(q);
178 y.resize(q);
179 for (int i = 0; i < q; i++)
180 {
181 assert(scanf("%d%d", &x[i], &y[i]) == 2);
182 }
183 fclose(stdin);
184
185 auto t2 = clock();
186
187 init(k, r);
188 for (int i = 0; i < q; i++)
189 {
190 answer[i] = compare_plants(x[i], y[i]);
191 }
192
193 auto t3 = clock();
194
195 for (int i = 0; i < q; i++)
196 {
197 printf("%d\n", answer[i]);
198 }
199
200 fclose(stdout);
201
202 auto t4 = clock();
203
204 std::clock_t c_end = std::clock();
205 auto t_end = std::chrono::high_resolution_clock::now();
206
CAPITOLUL 1. IOI 2020 18
121 }
122 ptr[p] = ord[ *(fr-1) ];
123 }
124 }
125
126 void init(int k, std::vector<int> r)
127 {
128 lexi_smallest(k,r,p_lt, tallest);
129 for(int &i: r) i = k-1-i;
130 lexi_smallest(k,r,p_rg, shortest);
131 }
132
133 int compare_plants(int x, int y)
134 {
135 if(x>y) return -compare_plants(y,x);
136 if(tallest[x]>tallest[y] || p_rg[y]>=shortest[x]) return -1;
137 if(shortest[x]>shortest[y] || p_lt[y]>=tallest[x]) return 1;
138 return 0;
139 }
140
141 // ---------------------------------------------------
142
143 int main()
144 {
145 std::clock_t c_start = std::clock();
146 auto t_start = std::chrono::high_resolution_clock::now();
147
148 auto t1 = clock();
149
150 std::freopen("../tests/7-15.in", "r", stdin) ;
151 std::freopen("plants.out", "w", stdout) ;
152
153 assert(scanf("%d%d%d", &n, &k, &q) == 3);
154
155 r.resize(n);
156 answer.resize(q);
157 for (int i = 0; i < n; i++)
158 {
159 int value;
160 assert(scanf("%d", &value) == 1);
161 r[i] = value;
162 }
163 x.resize(q);
164 y.resize(q);
165 for (int i = 0; i < q; i++)
166 {
167 assert(scanf("%d%d", &x[i], &y[i]) == 2);
168 }
169 fclose(stdin);
170
171 auto t2 = clock();
172
173 init(k, r);
174 for (int i = 0; i < q; i++)
175 {
176 answer[i] = compare_plants(x[i], y[i]);
177 }
178
179 auto t3 = clock();
180
181 for (int i = 0; i < q; i++)
182 {
183 printf("%d\n", answer[i]);
184 }
185
186 fclose(stdout);
187
188 auto t4 = clock();
189
190 std::clock_t c_end = std::clock();
191 auto t_end = std::chrono::high_resolution_clock::now();
192
193 // reset console output
194 freopen("CON", "w", stdout);
195
196 //std::cout <<result<<’\n’<<’\n’;
CAPITOLUL 1. IOI 2020 21
197 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
198 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
199 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
200
201 std::cout << std::fixed << std::setprecision(2)
202 << "\nCPU time used: "
203 << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"
204 << "Wall clock time passed: "
205 << std::chrono::duration<double, std::milli>(t_end-t_start).count()
206 << " ms\n";
207
208 return 0;
209 }
210 /*
211 t2-t1 = 1.035
212 t3-t2 = 1.15
213 t4-t3 = 0.089
214
215 CPU time used: 2274.00 ms
216 Wall clock time passed: 2273.99 ms
217
218 Process returned 0 (0x0) execution time : 2.326 s
219 Press any key to continue.
220 */
1.2 supertrees
Problema 2 - Connecting Supertrees 100 de puncte
Authors: Ranald Lam Yun Shao and Ling Yan Hao
Gardens by the Bay este un mare parc natural din Singapore. În parc sunt turnuri, cunoscute
ca supercopaci. Aceste turnuri sunt numerotate de la 0 la n 1. Vrem s construim o mulµime
CAPITOLUL 1. IOI 2020 24
constând în zero sau mai multe poduri. Fiecare pod conecteaz o pereche de turnuri distincte ³i
poate traversat în ambele direcµii. Nu este permis ca dou poduri s conecteze aceea³i pereche
de turnuri.
Un drum de la un turn x la un turn y este o secvenµ format din unul sau mai multe turnuri
astfel încât:
a primul element din secvenµ este x,
a ultimul element din secvenµ este y ,
a toate elementele din secvenµ sunt distincte, ³i
a ecare dou elemente consecutive (turnuri) din secvenµ sunt conectate printr-un pod.
Observaµi c , prin deniµie, exist exact un drum de la un turn la el însu³i ³i c num rul de
drumuri de la turnul i la turnul j este exact acela³i ca num rul de drumuri de la turnul j la turnul
i.
Arhitectul sef responsabil cu designul î³i dore³te ca podurile s e construite astfel încât oricare
ar 0 & i, j & n 1 s existe exact pij drumuri distincte de la turnul i la turnul j , unde
0 & pij & 3.
Construiµi o mulµime de poduri care satisfac condiµiile arhitectului ³ef, sau determinaµi c acest
lucru este imposibil.
Detalii de implementare
Trebuie s implementaµi urm toarea funcµie:
int construct(int[][] p)
void build(int[][] b)
Exemple
Exemplu 1 S consider m urm torul apel:
construct([[1, 1, 2, 2], [1, 1, 2, 2], [2, 2, 1, 2], [2, 2, 2, 1]])
Acesta înseamn c trebuie s existe exact un drum de la trunul 0 la turnul 1, iar pentru toate
celelalte perechi de turnuri x, y astfel încât 0 & x $ y & 3, trebuie s existe exact dou drumuri
de la turnul x la turnul y .
Condiµiile arhitectului ³ef pot întrunite construind 4 poduri, conectand perechile de turnuri
(0,1), (1,2), (1,3) ³i (2,3).
Pentru a raporta aceasta solutie, functia construct trebuie sa faca urmatorul apel:
a build([[0,1,0,0], [1,0,1,1], [0,1,0,1], [0,1,1,0]])
CAPITOLUL 1. IOI 2020 25
i apoi s returneze 1.
În acest caz exist mai multe construcµii care respect condiµiile, toate ind considerate corecte.
Acesta înseamn c trebuie s existe exact 3 drumuri între turnul 0 ³i turnul 1. în acest caz,
condiµiile nu pot satisf cute. Prin urmare, funcµia construct trebuie s returneze 0 f r s
apeleze niciodat funcµia build.
Restricµii
a 1 & n & 1000
a pii 1 (oricare ar 0 & i & n 1)
a pij pj i (oricare ar 0 & i, j & n 1)
a 0 & pij & 3 (oricare ar 0 & i, j & n 1)
Subtaskuri
1. (11 puncte) pij 1 (oricare ar 0 & i, j & n 1)
2. (10 puncte) pij 0 sau 1 (oricare ar 0 & i, j & n 1)
3. (19 puncte) pij 0 sau 2 (oricare ar i j j , 0 & i, j & n 1)
4. (35 de puncte) 0 & pij & 2 (oricare ar 0 & i, j & n 1) ³i exist cel puµin o construcµie
care satisface condiµiile.
5. (21 de puncte) 0 & pij & 2 (oricare ar 0 & i, j & n 1)
6. (4 puncte) F r restricµii suplimentare.
Sample grader
Graderul cite³te inputul în urm torul format:
a linia 1: n
a linia 2 i (0 & i & n 1): pi0 pi1 ... pin 1
Outputul graderului are urm torul format:
a linia 1: valoarea returnat de construct.
Dac valoarea returnat de construct este 1, atunci graderul mai a³eaz urm toarele:
a linia 2 i (0 & i & n 1): bi0 bi1 ... bin 1
CAPITOLUL 1. IOI 2020 26
Subtask 1
Construct any tree on nodes.
Subtask 2
We know that pij 0 if and only if i and j belong to dierent connected components. If
pij % 0 and pj k % 0, then we must have pik % 0; we may return impossible if this
condition is not satised.
Once this condition is satised, we proceed to identify the connected components and construct
any tree for each connected component.
Subtask 3
We proceed to identify the connected components as per the previous section. Instead of con-
structing a tree through each connected component, we construct a cycle instead.
Take note that connected components cannot have size 2; there are no cycles of length 2.
Subtask 4
As with the previous subtasks, we deal with each connected component separately.
For each i, consider the set of all j such that pij 1. For each of these sets, we construct
any tree through these nodes. For each of these trees, assign a special node which we will call the
`root'.
For each connected component, we now construct a cycle through these roots.
Subtask 5
We need to check for an additional condition: if pij 1 and pj k 1, then we must have
pik 1.
The previous checks from subtask 3 (consistency of connected components, no cycles of length
2) still apply as usual.
Subtask 6
¬ ¬
If pij 3 for some pair i, j , then there must be another pair i , j such that pi j
¬ ¬
' 4.
Therefore, this cannot occur.
We simply return 0 whenever this occurs.
11
12 using namespace std;
13
14 int construct(vector<vector<int>> p)
15 {
16 int n = p.size();
17 for (int i = 0; i < n; i++)
18 {
19 for (int j = 0; j < n; j++)
20 {
21 if (p[i][j] == 3) return 0;
22 }
23 }
24
25 vector<vector<int>> answer;
26 for (int i = 0; i < n; i++)
27 {
28 vector<int> row;
29 row.resize(n);
30 answer.push_back(row);
31 }
32
33 vector<bool> visited(n);
34 vector<int> componentIndex(n);
35 vector<int> lineIndex(n);
36 for (int aa = 0; aa < n; aa++)
37 {
38 if (visited[aa]) continue;
39 queue<int> qcomponent;
40 qcomponent.push(aa);
41 vector<int> cycle;
42 while (!qcomponent.empty())
43 {
44 int x = qcomponent.front();
45 qcomponent.pop();
46 if (visited[x]) continue;
47 vector<int> curline;
48 queue<int> qline;
49 qline.push(x);
50 cycle.push_back(x);
51 while (!qline.empty())
52 {
53 int y = qline.front();
54 qline.pop();
55 if (visited[y]) continue;
56 curline.push_back(y);
57 visited[y] = true;
58 componentIndex[y] = aa;
59 lineIndex[y] = x;
60 for (int i = 0; i < n; i++)
61 {
62 if (p[y][i] == 2)
63 qcomponent.push(i);
64 else if (p[y][i] == 1)
65 qline.push(i);
66 }
67 }
68
69 // for (int i : curline) printf("%d ", i); printf("\n");
70 if (curline.size() > 1)
71 {
72 for (int i = 0; i < (int)curline.size() - 1; i++)
73 {
74 int a = curline[i];
75 int b = curline[i + 1];
76 answer[a][b] = answer[b][a] = 1;
77 }
78 }
79 }
80
81 if (cycle.size() == 2) return 0;
82 if (cycle.size() == 1) continue;
83 for (int i = 0; i < (int)cycle.size(); i++)
84 {
85 int a = cycle[i];
86 int b = cycle[(i + 1) % cycle.size()];
CAPITOLUL 1. IOI 2020 28
87 answer[a][b] = answer[b][a] = 1;
88 }
89 }
90
91 for (int i = 0; i < n; i++)
92 {
93 for (int j = i + 1; j < n; j++)
94 {
95 if (lineIndex[i] == lineIndex[j])
96 {
97 if (p[i][j] != 1) return 0;
98 }
99 else
100 if (componentIndex[i] == componentIndex[j])
101 {
102 if (p[i][j] != 2) return 0;
103 }
104 else
105 {
106 if (p[i][j] != 0) return 0;
107 }
108 }
109 }
110
111 build(answer);
112
113 return 1;
114 }
115
116 // ---------------------------------------------------
117
118 static void check(bool cond, std::string message)
119 {
120 if (!cond)
121 {
122 printf("%s\n", message.c_str());
123 fclose(stdout);
124 exit(0);
125 }
126 }
127
128 void build(std::vector<std::vector<int>> _b)
129 {
130 check(!called, "build is called more than once");
131 called = true;
132 check((int)_b.size() == n, "Invalid number of rows in b");
133 for (int i = 0; i < n; i++)
134 {
135 check((int)_b[i].size() == n, "Invalid number of columns in b");
136 }
137 b = _b;
138 }
139
140 int main()
141 {
142 std::clock_t c_start = std::clock();
143 auto t_start = std::chrono::high_resolution_clock::now();
144
145 auto t1 = clock();
146
147 std::freopen("../tests/4-17.in", "r", stdin) ; //6-16, 4-17,
148 std::freopen("supertrees.out", "w", stdout) ;
149
150 assert(scanf("%d", &n) == 1);
151
152 p.resize(n);
153 for (int i = 0; i < n; i++)
154 {
155 p[i].resize(n);
156 }
157
158 for (int i = 0; i < n; i++)
159 {
160 for (int j = 0; j < n; j++)
161 {
162 assert(scanf("%d", &p[i][j]) == 1);
CAPITOLUL 1. IOI 2020 29
163 }
164 }
165 fclose(stdin);
166
167 auto t2 = clock();
168
169 int possible = construct(p);
170
171 auto t3 = clock();
172
173 check(possible == 0 || possible == 1, "Invalid return value of construct");
174 if (possible == 1)
175 {
176 check(called, "construct returned 1 without calling build");
177 }
178 else
179 {
180 check(!called, "construct called build but returned 0");
181 }
182
183 printf("%d\n", possible);
184 if (possible == 1)
185 {
186 for (int i = 0; i < n; i++)
187 {
188 for (int j = 0; j < n; j++)
189 {
190 if (j)
191 {
192 printf(" ");
193 }
194 printf("%d", b[i][j]);
195 }
196 printf("\n");
197 }
198 }
199 fclose(stdout);
200
201
202 auto t4 = clock();
203
204 std::clock_t c_end = std::clock();
205 auto t_end = std::chrono::high_resolution_clock::now();
206
207 // reset console output
208 freopen("CON", "w", stdout);
209
210 //std::cout <<result<<’\n’<<’\n’;
211 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
212 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
213 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
214
215 std::cout << std::fixed << std::setprecision(2)
216 << "\nCPU time used: "
217 << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"
218 << "Wall clock time passed: "
219 << std::chrono::duration<double, std::milli>(t_end-t_start).count()
220 << " ms\n";
221
222 return 0;
223 }
224 /*
225 t2-t1 = 1.468
226 t3-t2 = 0.016
227 t4-t3 = 0
228
229 CPU time used: 1484.00 ms
230 Wall clock time passed: 1484.36 ms
231
232 Process returned 0 (0x0) execution time : 1.531 s
233 Press any key to continue.
234 */
1 #include "testlib.h"
2 #include <bits/stdc++.h>
3
4 using namespace std;
5
6 //const std::string output_secret = "1f0934cc-cf56-429c-b010-8533ab3ded9e";
7
8 const int MAXP = 3;
9 const int MAXB = 1;
10
11 int n;
12 std::vector<std::vector<int>> p, b, b_adj;
13 vector<vector<int>> actual_ways;
14 vector<int> visited;
15
16 void too_many(int src, int dst)
17 {
18 quitf(
19 _wa,
20 "Too many ways to get from %d to %d, should be %d found no less than %d",
21 src,
22 dst,
23 p[src][dst],
24 actual_ways[src][dst]
25 );
26 }
27
28 void dfs(int src, int x)
29 {
30 visited[x] = 1;
31 // printf("in %d / ", x);
32 actual_ways[src][x] += 1;
33 if (actual_ways[src][x] > p[src][x])
34 {
35 too_many(src, x);
36 }
37 for (int i = 0; i < (int) b_adj[x].size(); i++)
38 {
39 if (!visited[b_adj[x][i]])
40 {
41 dfs(src, b_adj[x][i]);
42 }
43 }
44 // printf("out %d / ", x);
45 visited[x] = 0;
46 }
47
48 int main()
49 //int main(int argc, char * argv[])
50 {
51 int argc=4;
52
53 char* argv[] =
54 {
55 (char*)"checker",
56 (char*)"../tests/4-17.in", // input
57 (char*)"../tests/4-17.out", // rezultat corect
58 (char*)"supertrees.out", // rezultat de verificat si acordat punctaj
59 };
60
61 cout<<"argc = "<<argc<<"\n";
62 for(int kk=0;kk<argc;kk++)
63 cout<<argv[kk]<<"\n";
64 cout<<"----------------------\n";
65
66 registerChecker("supertrees", argc, argv);
67
68 //readBothSecrets(output_secret);
69 //readBothGraderResults();
70
71 //inf.readLine(); // Input Secret
72 n = inf.readInt();
73
74 int actual_possible = ans.readInt();
75 int possible = ouf.readInt();
76
CAPITOLUL 1. IOI 2020 31
77 if (actual_possible != possible)
78 {
79 quitf(_wa, "Answer gives possible %d while actual possible %d",
80 possible, actual_possible);
81 }
82
83 if (!possible)
84 {
85 quit(_ok);
86 }
87
88 p.resize(n);
89 b.resize(n);
90 b_adj.resize(n);
91 for (int i = 0; i < n; i++)
92 {
93 p[i] = inf.readInts(n, 0, MAXP, "p_i_j");
94 b[i] = ouf.readInts(n, 0, MAXB, "b_i_j");
95 for (int j = 0; j < n; j++)
96 {
97 if (b[i][j])
98 {
99 b_adj[i].push_back(j);
100 }
101 }
102 }
103
104 // Check that b is symmetric
105 for (int i = 0; i < n; i++)
106 {
107 for (int j = 0; j < n; j++)
108 {
109 if (b[i][j] != b[j][i])
110 {
111 quitf(_wa,
112 "b is not symmetric: b[%d][%d] (%d) != b[%d][%d] (%d)",
113 i, j, b[i][j], j, i, b[j][i]);
114 }
115 }
116 }
117
118 // Check that b diagonal is 0
119 for (int i = 0; i < n; i++)
120 {
121 if (b[i][i] != 0)
122 {
123 quitf(_wa, "b[%d][%d] is not 0", i, i);
124 }
125 }
126
127 // Populate actual_ways
128 actual_ways.resize(n);
129 for (int i = 0; i < n; i++)
130 {
131 actual_ways[i].resize(n, 0);
132 }
133 visited.resize(n, 0);
134
135 for (int i = 0; i < n; i++)
136 {
137 dfs(i, i);
138 }
139
140 for (int i = 0; i < n; i++)
141 {
142 for (int j = 0; j < n; j++)
143 {
144 if (p[i][j] != actual_ways[i][j])
145 {
146 quitf(
147 _wa,
148 "Too few ways to get from %d to %d, should be %d found %d",
149 i,
150 j,
151 p[i][j],
152 actual_ways[i][j]
CAPITOLUL 1. IOI 2020 32
153 );
154 }
155 }
156 }
157
158 quit(_ok);
159 }
160 /*
161 argc = 4
162 checker
163 ../tests/4-17.in
164 ../tests/4-17.out
165 supertrees.out
166 ----------------------
167 1
168 Correct
169
170 Process returned 0 (0x0) execution time : 1.159 s
171 Press any key to continue.
172 */
53
54 vector<int> curline;
55 queue<int> qline;
56
57 qline.push(x);
58 cycle.push_back(x);
59 while (!qline.empty())
60 {
61 int y = qline.front();
62 qline.pop();
63 if (visited[y]) continue;
64 curline.push_back(y);
65 visited[y] = true;
66 componentIndex[y] = aa;
67 lineIndex[y] = x;
68 for (int i = 0; i < n; i++)
69 {
70 if (p[y][i] == 2)
71 qcomponent.push(i);
72 else
73 if (p[y][i] == 1)
74 qline.push(i);
75 }
76 }
77
78 // for (int i : curline) printf("%d ", i); printf("\n");
79 if (curline.size() > 1)
80 {
81 for (int i = 0; i < (int)curline.size() - 1; i++)
82 {
83 int a = curline[i];
84 int b = curline[i + 1];
85 answer[a][b] = answer[b][a] = 1;
86 }
87 }
88 }
89
90 if (cycle.size() == 2) return 0;
91 if (cycle.size() == 1) continue;
92 for (int i = 0; i < (int)cycle.size(); i++)
93 {
94 int a = cycle[i];
95 int b = cycle[(i + 1) % cycle.size()];
96 answer[a][b] = answer[b][a] = 1;
97 }
98 }
99
100 for (int i = 0; i < n; i++)
101 {
102 for (int j = i + 1; j < n; j++)
103 {
104 if (lineIndex[i] == lineIndex[j])
105 {
106 if (p[i][j] != 1) return 0;
107 }
108 else
109 if (componentIndex[i] == componentIndex[j])
110 {
111 if (p[i][j] != 2) return 0;
112 }
113 else
114 {
115 if (p[i][j] != 0) return 0;
116 }
117 }
118 }
119
120 build(answer);
121 return 1;
122 }
123
124 // ---------------------------------------------------
125
126 static void check(bool cond, std::string message)
127 {
128 if (!cond)
CAPITOLUL 1. IOI 2020 34
129 {
130 printf("%s\n", message.c_str());
131 fclose(stdout);
132 exit(0);
133 }
134 }
135
136 void build(std::vector<std::vector<int>> _b)
137 {
138 check(!called, "build is called more than once");
139 called = true;
140 check((int)_b.size() == n, "Invalid number of rows in b");
141 for (int i = 0; i < n; i++)
142 {
143 check((int)_b[i].size() == n, "Invalid number of columns in b");
144 }
145 b = _b;
146 }
147
148 int main()
149 {
150 std::clock_t c_start = std::clock();
151 auto t_start = std::chrono::high_resolution_clock::now();
152
153 auto t1 = clock();
154
155 std::freopen("../tests/4-17.in", "r", stdin) ; //6-16, 4-17,
156 std::freopen("supertrees.out", "w", stdout) ;
157
158 assert(scanf("%d", &n) == 1);
159
160 p.resize(n);
161 for (int i = 0; i < n; i++)
162 {
163 p[i].resize(n);
164 }
165
166 for (int i = 0; i < n; i++)
167 {
168 for (int j = 0; j < n; j++)
169 {
170 assert(scanf("%d", &p[i][j]) == 1);
171 }
172 }
173 fclose(stdin);
174
175 auto t2 = clock();
176
177 int possible = construct(p);
178
179 auto t3 = clock();
180
181 check(possible == 0 || possible == 1, "Invalid return value of construct");
182 if (possible == 1)
183 {
184 check(called, "construct returned 1 without calling build");
185 }
186 else
187 {
188 check(!called, "construct called build but returned 0");
189 }
190
191 printf("%d\n", possible);
192 if (possible == 1)
193 {
194 for (int i = 0; i < n; i++)
195 {
196 for (int j = 0; j < n; j++)
197 {
198 if (j)
199 {
200 printf(" ");
201 }
202 printf("%d", b[i][j]);
203 }
204 printf("\n");
CAPITOLUL 1. IOI 2020 35
205 }
206 }
207 fclose(stdout);
208
209
210 auto t4 = clock();
211
212 std::clock_t c_end = std::clock();
213 auto t_end = std::chrono::high_resolution_clock::now();
214
215 // reset console output
216 freopen("CON", "w", stdout);
217
218 //std::cout <<result<<’\n’<<’\n’;
219 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
220 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
221 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
222
223 std::cout << std::fixed << std::setprecision(2)
224 << "\nCPU time used: "
225 << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"
226 << "Wall clock time passed: "
227 << std::chrono::duration<double, std::milli>(t_end-t_start).count()
228 << " ms\n";
229
230 return 0;
231 }
232 /*
233 t2-t1 = 1.359
234 t3-t2 = 0.125
235 t4-t3 = 0.437
236
237 CPU time used: 1921.00 ms
238 Wall clock time passed: 1921.87 ms
239
240 Process returned 0 (0x0) execution time : 1.969 s
241 Press any key to continue.
242 */
35
36 int cc = 0;
37 while (P[i][cc] != 1) cc++;
38
39 if (cc != i)
40 {
41 if (P[i] != P[cc])
42 {
43 return false;
44 }
45
46 answer[i][cc] = answer[cc][i] = true;
47 }
48 else
49 {
50 is_root[i] = true;
51 }
52 }
53
54 // check rectangles of nonzero’s
55 for (int i = 0; i < N; i++)
56 {
57 if (!is_root[i]) continue;
58
59 int cc = 0;
60 while (P[i][cc] == 0) cc++;
61 for (int j = 0; j < N; j++)
62 {
63 if ((P[i][j] == 0) != (P[cc][j] == 0))
64 {
65 return false;
66 }
67 }
68
69 if (cc == i)
70 {
71 int prv = i;
72 for (int j = i+1; j < N; j++)
73 {
74 if (is_root[j] && P[i][j])
75 {
76 answer[prv][j] = answer[j][prv] = true;
77 prv = j;
78 }
79 }
80
81 if (prv == i)
82 {
83 // do nothing
84 }
85 else
86 if (answer[i][prv])
87 {
88 return false;
89 }
90 else
91 {
92 answer[i][prv] = answer[prv][i] = true;
93 }
94 }
95 }
96
97 build(answer); return true;
98 }
99
100 // ---------------------------------------------------
101
102 static void check(bool cond, std::string message)
103 {
104 if (!cond)
105 {
106 printf("%s\n", message.c_str());
107 fclose(stdout);
108 exit(0);
109 }
110 }
CAPITOLUL 1. IOI 2020 37
111
112 void build(std::vector<std::vector<int>> _b)
113 {
114 check(!called, "build is called more than once");
115 called = true;
116 check((int)_b.size() == n, "Invalid number of rows in b");
117 for (int i = 0; i < n; i++)
118 {
119 check((int)_b[i].size() == n, "Invalid number of columns in b");
120 }
121 b = _b;
122 }
123
124 int main()
125 {
126 std::clock_t c_start = std::clock();
127 auto t_start = std::chrono::high_resolution_clock::now();
128
129 auto t1 = clock();
130
131 std::freopen("../tests/4-17.in", "r", stdin) ; //6-16, 4-17,
132 std::freopen("supertrees.out", "w", stdout) ;
133
134 assert(scanf("%d", &n) == 1);
135
136 p.resize(n);
137 for (int i = 0; i < n; i++)
138 {
139 p[i].resize(n);
140 }
141
142 for (int i = 0; i < n; i++)
143 {
144 for (int j = 0; j < n; j++)
145 {
146 assert(scanf("%d", &p[i][j]) == 1);
147 }
148 }
149 fclose(stdin);
150
151 auto t2 = clock();
152
153 int possible = construct(p);
154
155 auto t3 = clock();
156
157 check(possible == 0 || possible == 1, "Invalid return value of construct");
158 if (possible == 1)
159 {
160 check(called, "construct returned 1 without calling build");
161 }
162 else
163 {
164 check(!called, "construct called build but returned 0");
165 }
166
167 printf("%d\n", possible);
168 if (possible == 1)
169 {
170 for (int i = 0; i < n; i++)
171 {
172 for (int j = 0; j < n; j++)
173 {
174 if (j)
175 {
176 printf(" ");
177 }
178 printf("%d", b[i][j]);
179 }
180 printf("\n");
181 }
182 }
183 fclose(stdout);
184
185
186 auto t4 = clock();
CAPITOLUL 1. IOI 2020 38
187
188 std::clock_t c_end = std::clock();
189 auto t_end = std::chrono::high_resolution_clock::now();
190
191 // reset console output
192 freopen("CON", "w", stdout);
193
194 //std::cout <<result<<’\n’<<’\n’;
195 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
196 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
197 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
198
199 std::cout << std::fixed << std::setprecision(2)
200 << "\nCPU time used: "
201 << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"
202 << "Wall clock time passed: "
203 << std::chrono::duration<double, std::milli>(t_end-t_start).count()
204 << " ms\n";
205
206 return 0;
207 }
208 /*
209 t2-t1 = 1.5
210 t3-t2 = 0.141
211 t4-t3 = 0.593
212
213 CPU time used: 2234.00 ms
214 Wall clock time passed: 2234.37 ms
215
216 Process returned 0 (0x0) execution time : 2.281 s
217 Press any key to continue.
218 */
41 onecompNum[u] = onecomponents.size();
42 onecomponents.back().push_back(u);
43 for(int v = 0; v < n; v++)
44 if(!onevis[v] && p[u][v] == 1)
45 onedfs(v);
46 }
47
48 int construct(vector<vector<int>> p_)
49 {
50 p = p_;
51 n = p.size();
52
53 for (int i = 0; i < n; i++)
54 {
55 vector<int> row;
56 row.resize(n);
57 b.push_back(row);
58 }
59
60 vis.reset();
61
62 for(int i = 0; i < n; i++)
63 {
64 if(!vis[i])
65 {
66 components.push_back(vector<int>(0));
67 dfs(i);
68 }
69 }
70
71 for(int i = 0; i < n; i++)
72 {
73 if(!onevis[i])
74 {
75 onecomponents.push_back(vector<int>(0));
76 onedfs(i);
77 if(onecomponents.back().size() == 1)
78 {
79 onecompNum[i] = 0;
80 onecomponents.pop_back();
81 }
82 }
83 }
84
85 for(int i = 0; i < n; i++)
86 for(int j = 0; j < n; j++)
87 {
88 if(p[i][j] == 3) return 0;
89
90 if(compNum[i] == compNum[j] && p[i][j] == 0)
91 return 0;
92 else
93 if(compNum[i] != compNum[j] && p[i][j] > 0)
94 return 0;
95
96 if(onecompNum[i] == onecompNum[j] && onecompNum[i] != 0 && p[i][i] != 1)
97 return 0;
98 }
99
100 for(auto &v: components)
101 {
102 isOne.reset();
103 if(v.size() == 1)
104 continue;
105
106 vector<int> is[3];
107 for(auto &x: v)
108 if(onecompNum[x] == 0) is[2].push_back(x);
109
110 for(auto &x: v)
111 {
112 if(onecompNum[x] > 0)
113 {
114 auto &w = onecomponents[onecompNum[x]-1];
115 for(int i = 0; i+1 < (int)w.size(); i++)
116 {
CAPITOLUL 1. IOI 2020 40
117 b[w[i]][w[i+1]] = 1;
118 b[w[i+1]][w[i]] = 1;
119 }
120
121 is[2].push_back(w.back());
122 for(auto y: w)
123 onecompNum[y] = -1;
124 }
125 }
126
127 if(is[2].size() == 2) return 0;
128
129 if(is[2].size() > 2)
130 {
131 for(int i = 1; i < (int)is[2].size(); i++)
132 {
133 b[is[2][i-1]][is[2][i]] = 1;
134 b[is[2][i]][is[2][i-1]] = 1;
135 }
136
137 b[is[2][is[2].size()-1]][is[2][0]] = 1;
138 b[is[2][0]][is[2][is[2].size()-1]] = 1;
139 }
140 }
141
142 if(!possible)
143 return 0;
144
145 build(b);
146
147 return 1;
148 }
149
150 // ---------------------------------------------------
151
152 static void check(bool cond, std::string message)
153 {
154 if (!cond)
155 {
156 printf("%s\n", message.c_str());
157 fclose(stdout);
158 exit(0);
159 }
160 }
161
162 void build(std::vector<std::vector<int>> _b)
163 {
164 check(!called, "build is called more than once");
165 called = true;
166 check((int)_b.size() == n, "Invalid number of rows in b");
167 for (int i = 0; i < n; i++)
168 {
169 check((int)_b[i].size() == n, "Invalid number of columns in b");
170 }
171 b = _b;
172 }
173
174 int main()
175 {
176 std::clock_t c_start = std::clock();
177 auto t_start = std::chrono::high_resolution_clock::now();
178
179 auto t1 = clock();
180
181 std::freopen("../tests/4-17.in", "r", stdin) ; //6-16, 4-17,
182 std::freopen("supertrees.out", "w", stdout) ;
183
184 assert(scanf("%d", &n) == 1);
185
186 p.resize(n);
187 for (int i = 0; i < n; i++)
188 {
189 p[i].resize(n);
190 }
191
192 for (int i = 0; i < n; i++)
CAPITOLUL 1. IOI 2020 41
193 {
194 for (int j = 0; j < n; j++)
195 {
196 assert(scanf("%d", &p[i][j]) == 1);
197 }
198 }
199 fclose(stdin);
200
201 auto t2 = clock();
202
203 int possible = construct(p);
204
205 auto t3 = clock();
206
207 check(possible == 0 || possible == 1, "Invalid return value of construct");
208 if (possible == 1)
209 {
210 check(called, "construct returned 1 without calling build");
211 }
212 else
213 {
214 check(!called, "construct called build but returned 0");
215 }
216
217 printf("%d\n", possible);
218 if (possible == 1)
219 {
220 for (int i = 0; i < n; i++)
221 {
222 for (int j = 0; j < n; j++)
223 {
224 if (j)
225 {
226 printf(" ");
227 }
228 printf("%d", b[i][j]);
229 }
230 printf("\n");
231 }
232 }
233 fclose(stdout);
234
235
236 auto t4 = clock();
237
238 std::clock_t c_end = std::clock();
239 auto t_end = std::chrono::high_resolution_clock::now();
240
241 // reset console output
242 freopen("CON", "w", stdout);
243
244 //std::cout <<result<<’\n’<<’\n’;
245 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
246 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
247 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
248
249 std::cout << std::fixed << std::setprecision(2)
250 << "\nCPU time used: "
251 << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"
252 << "Wall clock time passed: "
253 << std::chrono::duration<double, std::milli>(t_end-t_start).count()
254 << " ms\n";
255
256 return 0;
257 }
258 /*
259 t2-t1 = 1.422
260 t3-t2 = 0.188
261 t4-t3 = 0.484
262
263 CPU time used: 2094.00 ms
264 Wall clock time passed: 2093.73 ms
265
266 Process returned 0 (0x0) execution time : 2.156 s
267 Press any key to continue.
268 */
CAPITOLUL 1. IOI 2020 42
75 dsu D2(n);
76 for(int x : v)
77 for(int y : v)
78 if(x != y && p[x][y] == 1)
79 D2.merge(x, y);
80
81 vector<int> cycle;
82 for(int x : v)
83 if(D2.par[x] == x)
84 {
85 cycle.push_back(x);
86 vector<int> U = D2.components[x];
87 int lst = -1;
88 for(int a : U)
89 {
90 for(int b : U)
91 if(p[a][b] != 1)
92 return 0;
93
94 if(lst != -1) add_edge(a, lst);
95 lst = a;
96 }
97 }
98
99 int m = cycle.size();
100 if(m == 2) return 0;
101 if(m > 1)
102 for(int k = 0; k < m; k++)
103 add_edge(cycle[k], cycle[(k + 1) % m]);
104 }
105
106 build(adj);
107
108 return 1;
109 }
110
111 // ---------------------------------------------------
112
113 static void check(bool cond, std::string message)
114 {
115 if (!cond)
116 {
117 printf("%s\n", message.c_str());
118 fclose(stdout);
119 exit(0);
120 }
121 }
122
123 void build(std::vector<std::vector<int>> _b)
124 {
125 check(!called, "build is called more than once");
126 called = true;
127 check((int)_b.size() == n, "Invalid number of rows in b");
128 for (int i = 0; i < n; i++)
129 {
130 check((int)_b[i].size() == n, "Invalid number of columns in b");
131 }
132 b = _b;
133 }
134
135 int main()
136 {
137 std::clock_t c_start = std::clock();
138 auto t_start = std::chrono::high_resolution_clock::now();
139
140 auto t1 = clock();
141
142 std::freopen("../tests/4-17.in", "r", stdin) ; //6-16, 4-17,
143 std::freopen("supertrees.out", "w", stdout) ;
144
145 assert(scanf("%d", &n) == 1);
146
147 p.resize(n);
148 for (int i = 0; i < n; i++)
149 {
150 p[i].resize(n);
CAPITOLUL 1. IOI 2020 44
151 }
152
153 for (int i = 0; i < n; i++)
154 {
155 for (int j = 0; j < n; j++)
156 {
157 assert(scanf("%d", &p[i][j]) == 1);
158 }
159 }
160 fclose(stdin);
161
162 auto t2 = clock();
163
164 int possible = construct(p);
165
166 auto t3 = clock();
167
168 check(possible == 0 || possible == 1, "Invalid return value of construct");
169 if (possible == 1)
170 {
171 check(called, "construct returned 1 without calling build");
172 }
173 else
174 {
175 check(!called, "construct called build but returned 0");
176 }
177
178 printf("%d\n", possible);
179 if (possible == 1)
180 {
181 for (int i = 0; i < n; i++)
182 {
183 for (int j = 0; j < n; j++)
184 {
185 if (j)
186 {
187 printf(" ");
188 }
189 printf("%d", b[i][j]);
190 }
191 printf("\n");
192 }
193 }
194 fclose(stdout);
195
196
197 auto t4 = clock();
198
199 std::clock_t c_end = std::clock();
200 auto t_end = std::chrono::high_resolution_clock::now();
201
202 // reset console output
203 freopen("CON", "w", stdout);
204
205 //std::cout <<result<<’\n’<<’\n’;
206 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
207 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
208 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
209
210 std::cout << std::fixed << std::setprecision(2)
211 << "\nCPU time used: "
212 << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"
213 << "Wall clock time passed: "
214 << std::chrono::duration<double, std::milli>(t_end-t_start).count()
215 << " ms\n";
216
217 return 0;
218 }
219 /*
220 t2-t1 = 1.625
221 t3-t2 = 0.063
222 t4-t3 = 0.453
223
224 CPU time used: 2141.00 ms
225 Wall clock time passed: 2140.62 ms
226
CAPITOLUL 1. IOI 2020 45
70 x[2] = 0;
71 x[3] = 0;
72 for(ll j = 0; j < sz; j++)
73 for(ll k = j + 1; k < sz; k++)
74 x[px[v[i][j]][v[i][k]]] = 1;
75
76 if(x[0] + x[1] + x[2] + x[3] == 0)
77 continue;
78 else
79 if(x[0])
80 bisa = 0;
81 else
82 if(x[2] == 1 && x[3] == 1)
83 bisa = 0;
84 else
85 if(x[1] == 1 && x[2] == 0 && x[3] == 0)
86 {
87 for(ll j = 1; j < sz; j++)
88 {
89 answer[v[i][j - 1]][v[i][j]] = 1;
90 answer[v[i][j]][v[i][j - 1]] = 1;
91 }
92 }
93 else
94 if(x[2] == 1)
95 {
96 ll te = 0;
97 for(ll j = 0; j < sz; j++)
98 {
99 if(kel[v[i][j]])
100 continue;
101
102 te++;
103 kel[v[i][j]] = te;
104 ket[te] = v[i][j];
105
106 for(ll k = 0; k < sz; k++)
107 {
108 if(j == k)
109 continue;
110
111 if(px[v[i][j]][v[i][k]] == 1)
112 {
113 kel[v[i][k]] = te;
114 answer[v[i][j]][v[i][k]] = 1;
115 answer[v[i][k]][v[i][j]] = 1;
116 }
117 }
118 }
119
120 for(ll j = 0; j < sz; j++)
121 for(ll k = j + 1; k < sz; k++)
122 {
123 if(px[v[i][j]][v[i][k]] == 1 && kel[v[i][j]] != kel[v[i][k]])
124 bisa = 0;
125
126 if(px[v[i][j]][v[i][k]] != 1 && kel[v[i][j]] == kel[v[i][k]])
127 bisa = 0;
128 }
129
130 if(te <= 2)
131 bisa = 0;
132
133 if(!bisa)
134 break;
135
136 for(ll j = 1; j < te; j++)
137 {
138 answer[ket[j]][ket[j + 1]] = 1;
139 answer[ket[j + 1]][ket[j]] = 1;
140 }
141
142 answer[ket[te]][ket[1]] = 1;
143 answer[ket[1]][ket[te]] = 1;
144 }
145 else
CAPITOLUL 1. IOI 2020 47
146 if(x[3] == 1)
147 {
148 bisa = 0;
149 }
150 }
151
152 if(!bisa)return 0;
153 build(answer);
154
155 return 1;
156 }
157
158 // ---------------------------------------------------
159
160 static void check(bool cond, std::string message)
161 {
162 if (!cond)
163 {
164 printf("%s\n", message.c_str());
165 fclose(stdout);
166 exit(0);
167 }
168 }
169
170 void build(std::vector<std::vector<int>> _b)
171 {
172 check(!called, "build is called more than once");
173 called = true;
174 check((int)_b.size() == n, "Invalid number of rows in b");
175 for (int i = 0; i < n; i++)
176 {
177 check((int)_b[i].size() == n, "Invalid number of columns in b");
178 }
179 b = _b;
180 }
181
182 int main()
183 {
184 std::clock_t c_start = std::clock();
185 auto t_start = std::chrono::high_resolution_clock::now();
186
187 auto t1 = clock();
188
189 std::freopen("../tests/4-17.in", "r", stdin) ; //6-16, 4-17,
190 std::freopen("supertrees.out", "w", stdout) ;
191
192 assert(scanf("%d", &n) == 1);
193
194 pp.resize(n);
195 for (int i = 0; i < n; i++)
196 {
197 pp[i].resize(n);
198 }
199
200 for (int i = 0; i < n; i++)
201 {
202 for (int j = 0; j < n; j++)
203 {
204 assert(scanf("%d", &pp[i][j]) == 1);
205 }
206 }
207 fclose(stdin);
208
209 auto t2 = clock();
210
211 int possible = construct(pp);
212
213 auto t3 = clock();
214
215 check(possible == 0 || possible == 1, "Invalid return value of construct");
216 if (possible == 1)
217 {
218 check(called, "construct returned 1 without calling build");
219 }
220 else
221 {
CAPITOLUL 1. IOI 2020 48
18 int f[N][4];
19 int Find(int x,int op)
20 {
21 if(f[x][op]==x) return x;
22 else return f[x][op]=Find(f[x][op],op);
23 }
24
25 void Union(int x,int y,int op)
26 {
27 x=Find(x,op),y=Find(y,op);
28 if(x==y) return;
29 f[y][op]=x;
30 }
31
32 int rol[N][N],len[N],vis[N][N];
33
34 int construct(std::vector<std::vector<int>> p)
35 {
36 int n = p.size();
37 for(int i=0;i<n;i++) f[i][1]=f[i][2]=i;
38 for(int i=0;i<n;i++)
39 {
40 for(int j=i+1;j<n;j++)
41 {
42 if(p[i][j]==3) return 0;
43 if(p[i][j]==1)
44 {
45 Union(i,j,1);
46 }
47 if(p[i][j]==2)
48 {
49 Union(i,j,2);
50 }
51 }
52 }
53
54 vector< vector<int> > ans;
55 for(int i=0;i<n;i++)
56 {
57 vector<int> row;
58 for(int j=0;j<n;j++) row.push_back(0);
59 ans.push_back(row);
60 }
61
62 for(int i=0;i<n;i++)
63 {
64 int t1=Find(i,1),t2=Find(t1,2);
65 if(t1!=t2 && Find(t1,1)==Find(t2,1))
66 {
67 f[t1][1]=t2,f[t2][1]=t2;
68 t1=t2;
69 }
70
71 if(t1!=i)
72 {
73 ans[t1][i]=ans[i][t1]=1;
74 }
75
76 if(t2!=t1)
77 {
78 if(!vis[t2][t1]) rol[t2][++len[t2]]=t1;
79 vis[t2][t1]=1;
80 }
81 }
82
83 //for(int i=0;i<n;i++) cout<<Find(i,1)<<" "<<Find(i,2)<<endl;
84 for(int i=0;i<n;i++)
85 {
86 if(len[i])
87 {
88 if(len[i]==1) return 0;
89 rol[i][0]=i;
90 for(int j=0;j<len[i];j++)
91 {
92 ans[rol[i][j]][rol[i][j+1]]=ans[rol[i][j+1]][rol[i][j]]=1;
93 }
CAPITOLUL 1. IOI 2020 50
11 static std::vector<std::vector<int>> p;
12 static std::vector<std::vector<int>> b;
13 static bool called = false;
14
15 // ---------------------------------------------------
16
17 int par[1010];
18 vector<int> ls[1010];
19
20 int fnd(int x) { return x == par[x] ? x : par[x] = fnd(par[x]); }
21 void uni(int x, int y) { par[fnd(x)] = fnd(y); }
22
23 int construct(vector<vector<int>> p)
24 {
25 int n = p.size();
26 vector<vector<int>> ret(n, vector<int>(n));
27
28 for(int i = 0; i < n; ++i) par[i] = i;
29 for(int i = 0; i < n; ++i)
30 {
31 for(int j = 0; j < n; ++j)
32 {
33 if(p[i][j] == 3) return 0;
34 if(p[i][j]) uni(i, j);
35 }
36 }
37
38 for(int i = 0; i < n; ++i) ls[fnd(i)].push_back(i);
39
40 for(int i = 0; i < n; ++i) if(ls[i].size())
41 {
42 vector<int> tmp = ls[i];
43 for(int j : tmp) for(int k : tmp) if(p[j][k] == 0) return 0;
44 for(int j : tmp) par[j] = j, ls[j].clear();
45 for(int j : tmp) for(int k : tmp) if(p[j][k] == 1) uni(j, k);
46 for(int j : tmp) ls[fnd(j)].push_back(j);
47
48 vector<int> head;
49 for(int j : tmp) if(ls[j].size())
50 {
51 head.push_back(j);
52 for(int k : ls[j]) for(int l : ls[j]) if(p[k][l] == 2) return 0;
53 for(int k = 0; k < (int)ls[j].size() - 1; ++k)
54 ret[ls[j][k]][ls[j][k + 1]] = ret[ls[j][k + 1]][ls[j][k]] = 1;
55 }
56
57 if(head.size() == 2) return 0;
58 if(head.size() >= 3)
59 {
60 for(int j = 0; j < (int)head.size() - 1; ++j)
61 ret[head[j]][head[j + 1]] = ret[head[j + 1]][head[j]] = 1;
62
63 ret[head.back()][head[0]] = ret[head[0]][head.back()] = 1;
64 }
65 }
66
67 build(ret);
68 return 1;
69 }
70
71 // ---------------------------------------------------
72
73 static void check(bool cond, std::string message)
74 {
75 if (!cond)
76 {
77 printf("%s\n", message.c_str());
78 fclose(stdout);
79 exit(0);
80 }
81 }
82
83 void build(std::vector<std::vector<int>> _b)
84 {
85 check(!called, "build is called more than once");
86 called = true;
CAPITOLUL 1. IOI 2020 53
46 {
47 if(p[i][j])
48 {
49 Num[j]=cnt;
50 }
51 }
52 }
53
54 for(i=0;i<n;i++)
55 {
56 for(j=0;j<n;j++)
57 {
58 if((Num[i]==Num[j])!=(p[i][j]!=0))return 0;
59 if(p[i][j]==3)return 0;
60 }
61 }
62
63 int cc=0;
64 for(i=0;i<n;i++)PPP[i]=-1;
65
66 vector<int>T;
67 for(i=0;i<n;i++)
68 {
69 if(!Num2[i])cc++;
70 else continue;
71
72 T.push_back(i);
73 for(j=0;j<n;j++)
74 {
75 if(p[i][j]==1)
76 {
77 Num2[j]=cc;
78 PPP[j]=i;
79 }
80 }
81 }
82
83 for(i=0;i<n;i++)
84 {
85 for(j=0;j<n;j++)
86 {
87 if(i==j)continue;
88 if((Num2[i]==Num2[j])!=(p[i][j]==1))return 0;
89 }
90 }
91
92 for(i=0;i<n;i++)
93 Add(i,PPP[i]);
94
95 for(auto &t : T)
96 {
97 vector<int>Z;
98 if(vis[t])continue;
99 for(auto &x : T)
100 if(!vis[x] && Num[t]==Num[x])
101 Z.push_back(x);
102
103 for(auto &x : Z)vis[x]=1;
104 int sz = Z.size();
105 if(sz==2)
106 return 0;
107
108 if(sz>1)
109 for(i=0;i<sz;i++)
110 Add(Z[i],Z[(i+1)%sz]);
111 }
112
113 build(E);
114
115 return 1;
116 }
117
118 // ---------------------------------------------------
119
120 static void check(bool cond, std::string message)
121 {
CAPITOLUL 1. IOI 2020 56
122 if (!cond)
123 {
124 printf("%s\n", message.c_str());
125 fclose(stdout);
126 exit(0);
127 }
128 }
129
130 void build(std::vector<std::vector<int>> _b)
131 {
132 check(!called, "build is called more than once");
133 called = true;
134 check((int)_b.size() == n, "Invalid number of rows in b");
135 for (int i = 0; i < n; i++)
136 {
137 check((int)_b[i].size() == n, "Invalid number of columns in b");
138 }
139 b = _b;
140 }
141
142 int main()
143 {
144 std::clock_t c_start = std::clock();
145 auto t_start = std::chrono::high_resolution_clock::now();
146
147 auto t1 = clock();
148
149 std::freopen("../tests/4-17.in", "r", stdin) ; //6-16, 4-17,
150 std::freopen("supertrees.out", "w", stdout) ;
151
152 assert(scanf("%d", &n) == 1);
153
154 p.resize(n);
155 for (int i = 0; i < n; i++)
156 {
157 p[i].resize(n);
158 }
159
160 for (int i = 0; i < n; i++)
161 {
162 for (int j = 0; j < n; j++)
163 {
164 assert(scanf("%d", &p[i][j]) == 1);
165 }
166 }
167 fclose(stdin);
168
169 auto t2 = clock();
170
171 int possible = construct(p);
172
173 auto t3 = clock();
174
175 check(possible == 0 || possible == 1, "Invalid return value of construct");
176 if (possible == 1)
177 {
178 check(called, "construct returned 1 without calling build");
179 }
180 else
181 {
182 check(!called, "construct called build but returned 0");
183 }
184
185 printf("%d\n", possible);
186 if (possible == 1)
187 {
188 for (int i = 0; i < n; i++)
189 {
190 for (int j = 0; j < n; j++)
191 {
192 if (j)
193 {
194 printf(" ");
195 }
196 printf("%d", b[i][j]);
197 }
CAPITOLUL 1. IOI 2020 57
198 printf("\n");
199 }
200 }
201 fclose(stdout);
202
203
204 auto t4 = clock();
205
206 std::clock_t c_end = std::clock();
207 auto t_end = std::chrono::high_resolution_clock::now();
208
209 // reset console output
210 freopen("CON", "w", stdout);
211
212 //std::cout <<result<<’\n’<<’\n’;
213 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
214 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
215 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
216
217 std::cout << std::fixed << std::setprecision(2)
218 << "\nCPU time used: "
219 << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"
220 << "Wall clock time passed: "
221 << std::chrono::duration<double, std::milli>(t_end-t_start).count()
222 << " ms\n";
223
224 return 0;
225 }
226 /*
227 t2-t1 = 1.265
228 t3-t2 = 0.125
229 t4-t3 = 0.438
230
231 CPU time used: 1828.00 ms
232 Wall clock time passed: 1828.12 ms
233
234 Process returned 0 (0x0) execution time : 1.891 s
235 Press any key to continue.
236 */
1.3 tickets
Problema 3 - Carnival Tickets 100 de puncte
Author: Xiao Mao
Ringo este la un carnaval în Singapore. El are câteva bilete în bagaj, pe care vrea s le
foloseasc la un stand cu jocuri. Fiecare bilet are o culoare din cele n culori posibile ³i are un
întreg nenegativ imprimat pe el. întregul imprimat poate acela³i pentru mai multe dintre bilete.
Datorit unei ciud µenii în regulile carnavalului, n este garantat par.
Ringo are câte m bilete de ecare culoare în bagaj, pentru un total de n m bilete. Biletul j
de culoare i are întregul xij imprimat pe el (0 & i & n 1 ³i 0 & j & m 1).
Jocul se joac în k runde, numerotate de la 0 la k 1. Fiecare rund este jucat în ordinea
urm toare:
Din bagaj, Ringo selecteaz o mulµime de n bilete, un bilet din ecare culoare. El d apoi
biletele responsabilului de la stand.
Responsabilul standului noteaz întregii a0, a1, ..., an 1 imprimaµi pe biletele din
mulµime. Ordinea acestor n întregi nu este important .
Responsabilul standului extrage o carte special dintr-o cutie ³i noteaz întregul b imprimat
pe aceast carte.
Responsabilul standului calculeaz modulul diferenµei dintre ai ³i b pentru ecare i de la
0 la n 1. Fie S suma acestor module.
Pentru aceast rund , responsabilul standului îi d lui Ringo un premiu în valoare egal cu
S.
CAPITOLUL 1. IOI 2020 58
Biletele din mulµime sunt aruncate ³i nu mai pot folosite în rundele urm toare.
Biletele r mase în bagajul lui Ringo dup k runde ale jocului sunt aruncate.
Privind cu atenµie, Ringo realizeaz c jocul este trucat! Exist de fapt o imprimant în
interiorul cutiei din care se extrage cartea special . În ecare rund , responsabilul standului
g se³te un întreg b care minimizeaz valoarea premiului pentru acea rund . Valoarea aleas de
responsabilul standului este imprimat pe cartea extras în acea rund .
Având toate aceste informaµii, Ringo ar dori s aloce biletele pentru rundele jocului. Mai exact,
acesta dore³te s selecteze mulµimea de bilete folosit în ecare rund astfel încât s maximizeze
valoarea total a premiilor.
Detalii de implementare
Trebuie s implementaµi urm toarea funcµie:
k : num rul rundelor.
x: o matrice de dimensiuni n m conµinând întregii de pe bilete. Biletele de ecare culoare
sunt sortate în ordinea cresc toare a întregilor imprimaµi pe ele.
Aceast funcµie este apelat o singur dat .
Aceast funcµie trebuie s fac un singur apel c tre allocate_tickets (vezi mai jos),
pentru k mulµimi de bilete, unul pentru ecare rund .
Aceast funcµie trebuie s returneze valoarea maxim a premiilor.
void allocate_tickets(int[][] s)
s: o matrice de dimensiuni n m. Valoarea lui sij este r dac biletul j de culoare i este
utilizat în mulµimea rundei r a jocului, sau -1 dac nu este folosit deloc.
Pentru ecare 0 & i & n 1, printre si0, si1, ..., sim 1 ecare valoare 0, 1, 2,
..., k 1 trebuie s apar o singur dat , iar celelalte valori s e -1.
Dac exist mai multe aloc ri pentru valoarea maxim a premiului, se poate raporta oricare.
Exemple
Exemplul 1 Consider m urm torul apel:
find_maximum(2, [[0, 2, 5],[1, 1, 3]])
Pentru a raporta aceast alocare, funcµia find_maximum ar trebui s fac urm torul apel
c tre allocate_tickets:
a allocate_tickets([[0, -1, 1], [-1, 1, 0]])
În nal, funcµia find_maximum trebuie s returneze .
Pentru a raporta aceast alocare, funcµia find_maximum ar trebui s fac urm torul apel
c tre allocate_tickets:
a allocate_tickets([[-1, 0], [0, -1], [0, -1], [-1, 0]])
Restricµii
2 & n & 1500 ³i n este par.
1 & k & m & 1500
0 & xij & 10 (oricare ar 0 & i & n 1 si 0 & j & m 1)
9
xij 1 & xij (oricare ar 0 & i & n 1 si 0 & j & m 1)
Subtaskuri
1. (11 puncte) m 1
2. (16 puncte) k 1
3. (14 puncte) 0 & xij & 1 (oricare ar 0 & i & n 1 si 0 & j &m1 )
4. (14 puncte) k m
5. (12 puncte) n, m & 80
6. (23 puncte) n, m & 300
7. (10 puncte) F r restricµii suplimentare.
Sample grader
Sample graderul cite³te intr rile în urm torul format:
linia 1: n m k
linia 2 i (0 & i & n 1): xi0 xi1 ... xim 1)
Observe that the special card pulled by the game master is always equal to the it median of the
input.
Since n is even, we may assume that the value of each prize is given by the sum of the top half
values, minus the sum of the bottom values.
We can now change the rules as follows(*):
On each round, 1 ticket of each color is chosen.
These n tickets are split into two piles labeled '+' and '-'.
CAPITOLUL 1. IOI 2020 60
It is easy to see that a player who wishes to maximize the value of his prize will choose to put
the tickets of larger value into the `+' pile. By doing so, the value of the prize remains the same
as compared to the original version.
It is in fact convenient to relax the rules even further and combine the k rounds into a single
round(**):
These kn tickets are split into two piles labeled '+' and '-', each pile consisting of kn©2
tickets
The value of the prize is given by the sum of all tickets labeled '+', minus the sum of all
tickets labeled '-'.
It is clear that the maximal attainable value using the rules in (**) is at least as large the
maximal value attainable in (*): this is because we can simply merge the '+' and '-' piles.
We claim that they are in fact equal (this would solve subtask 4).
To show that they are equal, we need a method for `splitting' up these tickets back into k piles.
Starting with the kn©2 tickets, we proceed as follows until all the tickets are split into k rounds:
Sort the colors by the total number of '+' in each pile.
For each of the colors with the most total number of '+', take 1 ticket with a '+' label from
each of them. For the remaining numbers, take 1 ticket with a '-' label.
Collect the tickets from the previous step, and form 1 round with it.
101 (
102 pii
103 (
104 d_o(this_company, s - 1 - plus_count[this_company])
105 + d_o(this_company, k - 1 - plus_count[this_company]),
106 this_company
107 )
108 );
109 }
110 }
111
112 // Empty out the priority queue, will use again later
113 while (!gain.empty()) gain.pop();
114
115 // gain: (+s remaining, company index)
116 for (int i = 0; i < c; i++)
117 {
118 gain.push(pii(plus_count[i], i));
119 }
120
121 // minus_count[company] => How many -s the company has sent so far
122 vector<int> minus_count;
123 minus_count.resize(c, 0);
124
125 // Prepare answer vector dimensions and fill with -1s
126 vector<vector<int>> answer;
127 answer.resize(c);
128 for (int i = 0; i < c; i++)
129 {
130 answer[i].resize(s, -1);
131 }
132
133 // take[company] => Does this company send a + in this days
134 vector<int> take;
135 take.resize(c, 0);
136
137 // Simulate k days of tickets
138 for (int i = 0; i < k; i++)
139 {
140 // Pick c/2 companies with the most +s left
141 for (int j = 0; j < c / 2; j ++)
142 {
143 take[gain.top().second] = 1;
144 gain.pop();
145 }
146
147 // Check if each company sent a - or +, and change answer accordingly
148 for (int j = 0; j < c; j++)
149 {
150 if (take[j])
151 {
152 // Company j sent a + this round, send the smallest +
153 // Queue the company back
154 answer[j][o[j][s - plus_count[j]]] = i;
155 plus_count[j]--;
156 gain.push(pii(plus_count[j], j));
157 }
158 else
159 {
160 // Company j sent a - this round, send the smallest -
161 answer[j][o[j][minus_count[j]]] = i;
162 minus_count[j]++;
163 }
164 take[j] = 0;
165 }
166 }
167
168 // Return to grader
169 allocate_tickets(answer);
170
171 return cost;
172 }
173
174 // ---------------------------------------------------
175
176 static void check(bool cond, std::string message)
CAPITOLUL 1. IOI 2020 63
177 {
178 if (!cond)
179 {
180 printf("%s\n", message.c_str());
181 exit(0);
182 }
183 }
184
185 void allocate_tickets( std::vector<std::vector<int>> _d)
186 {
187 check(!called, "allocate_tickets called more than once");
188 d = _d;
189 check((int)d.size() == n,
190 "allocate_tickets called with parameter of wrong size");
191 for (int i = 0; i < n; i++)
192 {
193 check((int)d[i].size() == m,
194 "allocate_tickets called with parameter of wrong size");
195 }
196 called = 1;
197 }
198
199 int main()
200 {
201 std::clock_t c_start = std::clock();
202 auto t_start = std::chrono::high_resolution_clock::now();
203
204 auto t1 = clock();
205
206 std::freopen("../tests/7-14.in", "r", stdin) ;
207 std::freopen("tickets.out", "w", stdout) ;
208
209 assert(scanf("%d %d %d", &n, &m, &k) == 3);
210 x.resize(n);
211 for (int i = 0; i < n; i++)
212 {
213 x[i].resize(m);
214 for (int j=0; j < m; j++)
215 {
216 assert(scanf("%d", &x[i][j]) == 1);
217 }
218 }
219 fclose(stdin);
220
221 auto t2 = clock();
222
223 long long answer = find_maximum(k, x);
224
225 auto t3 = clock();
226
227 check(called, "failure to call allocate_tickets");
228
229 printf("%lld\n", answer);
230 for (int i = 0; i < n; i++)
231 {
232 for (int j = 0; j < m; j++)
233 {
234 if (j) printf(" ");
235 printf("%d", d[i][j]);
236 }
237 printf("\n");
238 }
239 fclose(stdout);
240
241 auto t4 = clock();
242
243 std::clock_t c_end = std::clock();
244 auto t_end = std::chrono::high_resolution_clock::now();
245
246 // reset console output
247 freopen("CON", "w", stdout);
248
249 //std::cout <<result<<’\n’<<’\n’;
250 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
251 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
252 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
CAPITOLUL 1. IOI 2020 64
253
254 std::cout << std::fixed << std::setprecision(2)
255 << "\nCPU time used: "
256 << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"
257 << "Wall clock time passed: "
258 << std::chrono::duration<double, std::milli>(t_end-t_start).count()
259 << " ms\n";
260
261 return 0;
262 }
263 /*
264 t2-t1 = 4.423
265 t3-t2 = 4.341
266 t4-t3 = 1.237
267
268 CPU time used: 10001.00 ms
269 Wall clock time passed: 10001.12 ms
270
271 Process returned 0 (0x0) execution time : 10.065 s
272 Press any key to continue.
273 */
128 ----------------------
129 1
130 Correct
131
132 Process returned 0 (0x0) execution time : 4.211 s
133 Press any key to continue.
134 */
66 }
67 else if (sgn[i][j] < 0)
68 {
69 neg[i].push(j);
70 ret -= x[i][j];
71 }
72 }
73 }
74
75 vector<int> level(n, -1);
76 vector<vector<int>> answer(n, vector<int>(m, -1));
77
78 for (int rep = 0; rep < k; ++rep)
79 {
80 int val = 0;
81 for (int i = 0; i < n; ++i)
82 {
83 if (pos[i].empty())
84 {
85 --val;
86 answer[i][neg[i].front()] = rep;
87 neg[i].pop();
88 level[i] = rep;
89 }
90 else if (neg[i].empty())
91 {
92 ++val;
93 answer[i][pos[i].front()] = rep;
94 pos[i].pop();
95 level[i] = rep;
96 }
97 }
98
99 for (int i = 0; i < n; ++i)
100 {
101 if (level[i] == rep) continue;
102 if (val < 0)
103 {
104 ++val;
105 answer[i][pos[i].front()] = rep;
106 pos[i].pop();
107 }
108 else
109 {
110 --val;
111 answer[i][neg[i].front()] = rep;
112 neg[i].pop();
113 }
114 }
115 }
116
117 allocate_tickets(answer);
118
119 return ret;
120 }
121
122 // ---------------------------------------------------
123
124 static void check(bool cond, std::string message)
125 {
126 if (!cond)
127 {
128 printf("%s\n", message.c_str());
129 exit(0);
130 }
131 }
132
133 void allocate_tickets( std::vector<std::vector<int>> _d)
134 {
135 check(!called, "allocate_tickets called more than once");
136 d = _d;
137 check((int)d.size() == n,
138 "allocate_tickets called with parameter of wrong size");
139 for (int i = 0; i < n; i++)
140 {
141 check((int)d[i].size() == m,
CAPITOLUL 1. IOI 2020 68
218
219 Process returned 0 (0x0) execution time : 6.658 s
220 Press any key to continue.
221 */
69 }
70 else if (num_hi[i] == 0)
71 {
72 c0++;
73 }
74 else
75 {
76 // do nothing
77 }
78 }
79
80 assert(c0 <= N/2 && c1 <= N/2);
81 for (int i = 0; i < N; i++)
82 {
83 int d;
84 if (num_hi[i] == k+1)
85 {
86 d = 1;
87 }
88 else if (num_hi[i] == 0)
89 {
90 d = 0;
91 }
92 else if (c0 < N/2)
93 {
94 c0++;
95 d = 0;
96 }
97 else if (c1 < N/2)
98 {
99 c1++;
100 d = 1;
101 }
102 else assert(false);
103
104 if (d)
105 {
106 answer[i][M - (num_hi[i]--)] = k;
107 }
108 else
109 {
110 answer[i][k - num_hi[i]] = k;
111 }
112 }
113 }
114
115 allocate_tickets(answer);
116
117 return tot_val;
118 }
119
120 // ---------------------------------------------------
121
122 static void check(bool cond, std::string message)
123 {
124 if (!cond)
125 {
126 printf("%s\n", message.c_str());
127 exit(0);
128 }
129 }
130
131 void allocate_tickets( std::vector<std::vector<int>> _d)
132 {
133 check(!called, "allocate_tickets called more than once");
134 d = _d;
135 check((int)d.size() == n,
136 "allocate_tickets called with parameter of wrong size");
137 for (int i = 0; i < n; i++)
138 {
139 check((int)d[i].size() == m,
140 "allocate_tickets called with parameter of wrong size");
141 }
142 called = 1;
143 }
144
CAPITOLUL 1. IOI 2020 71
151 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
152
153 std::cout << std::fixed << std::setprecision(2)
154 << "\nCPU time used: "
155 << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"
156 << "Wall clock time passed: "
157 << std::chrono::duration<double, std::milli>(t_end-t_start).count()
158 << " ms\n";
159
160 return 0;
161 }
162 /*
163 t2-t1 = 4.702
164 t3-t2 = 3.39
165 t4-t3 = 1.203
166
167 CPU time used: 9295.00 ms
168 Wall clock time passed: 9295.29 ms
169
170 Process returned 0 (0x0) execution time : 9.358 s
171 Press any key to continue.
172 */
51
52 Ans += x;
53
54 if(k - r >= 0)
55 q.emplace(a[i][m - r] + a[i][k - r], pii(i, j - 1));
56 }
57
58 vector <vector <int>> s(n, vector <int> (m, -1));
59
60 vector <pii> Sum(k);
61 for(int j = 0; j < k; j++) Sum[j] = pii(0, j);
62
63 for(int i = 0; i < n; i++)
64 {
65 for(int j = 0; j < PrefixTaken[i]; j++)
66 {
67 Sum[k - j - 1].first--;
68 s[i][j] = Sum[k - j - 1].second;
69 }
70
71 for(int j = 0; j < SuffixTaken[i]; j++)
72 {
73 Sum[j].first++;
74 s[i][m - j - 1] = Sum[j].second;
75 }
76
77 sort(Sum.begin(), Sum.end());
78 }
79
80 for(int j = 0; j < k; j++)
81 assert(Sum[j].first == 0);
82
83 return allocate_tickets(s), Ans;
84 }
85
86 // ---------------------------------------------------
87
88 static void check(bool cond, std::string message)
89 {
90 if (!cond)
91 {
92 printf("%s\n", message.c_str());
93 exit(0);
94 }
95 }
96
97 void allocate_tickets( std::vector<std::vector<int>> _d)
98 {
99 check(!called, "allocate_tickets called more than once");
100 d = _d;
101 check((int)d.size() == n,
102 "allocate_tickets called with parameter of wrong size");
103 for (int i = 0; i < n; i++)
104 {
105 check((int)d[i].size() == m,
106 "allocate_tickets called with parameter of wrong size");
107 }
108 called = 1;
109 }
110
111 int main()
112 {
113 std::clock_t c_start = std::clock();
114 auto t_start = std::chrono::high_resolution_clock::now();
115
116 auto t1 = clock();
117
118 std::freopen("../tests/7-14.in", "r", stdin) ;
119 std::freopen("tickets.out", "w", stdout) ;
120
121 assert(scanf("%d %d %d", &n, &m, &k) == 3);
122 x.resize(n);
123 for (int i = 0; i < n; i++)
124 {
125 x[i].resize(m);
126 for (int j=0; j < m; j++)
CAPITOLUL 1. IOI 2020 76
127 {
128 assert(scanf("%d", &x[i][j]) == 1);
129 }
130 }
131 fclose(stdin);
132
133 auto t2 = clock();
134
135 long long answer = find_maximum(k, x);
136
137 auto t3 = clock();
138
139 check(called, "failure to call allocate_tickets");
140
141 printf("%lld\n", answer);
142 for (int i = 0; i < n; i++)
143 {
144 for (int j = 0; j < m; j++)
145 {
146 if (j) printf(" ");
147 printf("%d", d[i][j]);
148 }
149 printf("\n");
150 }
151 fclose(stdout);
152
153 auto t4 = clock();
154
155 std::clock_t c_end = std::clock();
156 auto t_end = std::chrono::high_resolution_clock::now();
157
158 // reset console output
159 freopen("CON", "w", stdout);
160
161 //std::cout <<result<<’\n’<<’\n’;
162 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
163 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
164 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
165
166 std::cout << std::fixed << std::setprecision(2)
167 << "\nCPU time used: "
168 << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"
169 << "Wall clock time passed: "
170 << std::chrono::duration<double, std::milli>(t_end-t_start).count()
171 << " ms\n";
172
173 return 0;
174 }
175 /*
176 t2-t1 = 4.326
177 t3-t2 = 2.063
178 t4-t3 = 1.203
179
180 CPU time used: 7592.00 ms
181 Wall clock time passed: 7592.16 ms
182
183 Process returned 0 (0x0) execution time : 7.655 s
184 Press any key to continue.
185 */
90
91 static void check(bool cond, std::string message)
92 {
93 if (!cond)
94 {
95 printf("%s\n", message.c_str());
96 exit(0);
97 }
98 }
99
100 void allocate_tickets( std::vector<std::vector<int>> _d)
101 {
102 check(!called, "allocate_tickets called more than once");
103 dd = _d;
104 check((int)dd.size() == n,
105 "allocate_tickets called with parameter of wrong size");
106 for (int i = 0; i < n; i++)
107 {
108 check((int)dd[i].size() == m,
109 "allocate_tickets called with parameter of wrong size");
110 }
111 called = 1;
112 }
113
114 int main()
115 {
116 std::clock_t c_start = std::clock();
117 auto t_start = std::chrono::high_resolution_clock::now();
118
119 auto t1 = clock();
120
121 std::freopen("../tests/7-14.in", "r", stdin) ;
122 std::freopen("tickets.out", "w", stdout) ;
123
124 assert(scanf("%d %d %d", &n, &m, &k) == 3);
125 x.resize(n);
126 for (int i = 0; i < n; i++)
127 {
128 x[i].resize(m);
129 for (int j=0; j < m; j++)
130 {
131 assert(scanf("%d", &x[i][j]) == 1);
132 }
133 }
134 fclose(stdin);
135
136 auto t2 = clock();
137
138 long long answer = find_maximum(k, x);
139
140 auto t3 = clock();
141
142 check(called, "failure to call allocate_tickets");
143
144 printf("%lld\n", answer);
145 for (int i = 0; i < n; i++)
146 {
147 for (int j = 0; j < m; j++)
148 {
149 if (j) printf(" ");
150 printf("%d", dd[i][j]);
151 }
152 printf("\n");
153 }
154 fclose(stdout);
155
156 auto t4 = clock();
157
158 std::clock_t c_end = std::clock();
159 auto t_end = std::chrono::high_resolution_clock::now();
160
161 // reset console output
162 freopen("CON", "w", stdout);
163
164 //std::cout <<result<<’\n’<<’\n’;
165 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
CAPITOLUL 1. IOI 2020 79
166 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
167 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
168
169 std::cout << std::fixed << std::setprecision(2)
170 << "\nCPU time used: "
171 << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"
172 << "Wall clock time passed: "
173 << std::chrono::duration<double, std::milli>(t_end-t_start).count()
174 << " ms\n";
175
176 return 0;
177 }
178 /*
179 t2-t1 = 4.734
180 t3-t2 = 1.993
181 t4-t3 = 1.422
182
183 CPU time used: 8149.00 ms
184 Wall clock time passed: 8149.66 ms
185
186 Process returned 0 (0x0) execution time : 8.197 s
187 Press any key to continue.
188 */
1.4 biscuits
Problema 4 - Packing Biscuits 100 de puncte
Author: Mikhail Tikhomirov
Detalii de implementare
Trebuie s implementaµi urm toarea funcµie:
Exemple
Exemplul 1 S consider m apelul urm tor:
count_tastiness(3, [5, 2, 1])
CAPITOLUL 1. IOI 2020 80
Acesta înseamn c M tu³a dore³te s împacheteze 3 pungi, ³i exist 3 tipuri de biscuiµi în magazin:
5 biscuiµi de tip 0, ecare având valoarea aromei 1,
2 biscuiµi de tip 1, ecare având valoarea aromei 2,
1 biscuit de tip 2, ecare având valoarea aromei 4.
Valorile y posibile sunt 0, 1, 2, 3, 4. De exemplu, pentru a împacheta 3 pungi cu totalul
aromelor având valoarea 3, M tu³a poate împacheta:
o pung ce conµine trei biscuiµi de tip 0 ³i
dou pungi, ecare conµinând câte un biscuit de tip 0 ³i un biscuit de tip 1.
Valorile posibile sunt 0, 1, 2, 4, 5, 6. Deoarece exist 6 valori posibile pentru y , funcµia va
trebui s returneze valoarea 6.
Restricµii
1 & k & 60
1 & q & 1000
1 & x & 10
18
0 & ai & 10 (for all 0 & i & k 1)
18
Pentru ecare apel al count_tastiness, suma valorilor aromelor tuturor biscuiµilor din
18
c mar nu va dep ³i 10 .
Subtaskuri
1. (9 puncte) q & 10, ³i pentru ecare apel al count_tastiness, valorilor aromelor tuturor
biscuiµilor din c mar nu dep ³e³te 100 000.
2. (12 puncte) x 1, 1 & 10
3. (21 de puncte) x & 10 000, q & 10
4. (35 de puncte) Pentru ecare apel al count_tastiness rezultatul corect nu dep ³e³te
200 000.
5. (23 de puncte) F r restricµii suplimentare.
Sample grader
Sample graderul cite³te intrarea în formatul urm tor. Prima linie conµine un întreg q . Dup aceea,
urmeaz q perechi de linii, ecare pereche reprezentând câte un scenariu în urm torul format:
linia 1: k x
linia 2: a0 a1 ... ak 1
CAPITOLUL 1. IOI 2020 81
Subtask 1
We proceed by checking every value of y , noting that y & 10 . For each value of y , we use the
5
Subtask 2
We begin with the following observation:
If ai ' 3, the solution remains unchanged if we decrease ai by 2 and increase ai 1 by
1.
Using this observation, we may combine smaller biscuits into bigger ones such that ai "
r0, 1, 2x.
A second observation is the following:
Suppose ai 0 for some i. Let y be any integer, we perform division with remainder and
i i
write y 2 q r. Then y is good if and only if 2 q is good and r is good.
Suppose ai j 0 for all i. Then for any integer y , y is good if and only if the total tastiness
is at least y .
Using this observation, we may split the input into consecutive segments of non-zero values.
The nal answer is the product of the answers individual segments.
Subtask 3
Similar to the previous subtask, if ai ' x 2, we may decrement ai by 2 and increase ai 1
by 1.
We now proceed by dynamic programming. Let f n, i be the answer if we replace a0, a1,
..., ai 1 by 0 and increment ai by n.
We obtain the following recurrence relation:
n ai $ x
nai
f &,i 1
f 0, 60 1, f n, i w 2
1 n ai ' x
nai naix
f 2
&,i 1 f 2
&,i
To explain the relation, let S be the set of all valid y when a0, a1, ..., ai 1 are replaced
by 0 and ai incremented by n.
i1 i
If y is a multiple of 2 , then the biscuits of tastiness 2 must be used in pairs. We therefore
i1
merge pairs of biscuits to make biscuits of tastiness 2 .
i1 i
If y is not a multiple of 2 but not a multiple of 2 , then we need to use x biscuits of tastiness
i
2 . The remaining ai n x biscuits must be used up in pairs.
i
If y is not a multiple of 2 , then y cannot be good.
CAPITOLUL 1. IOI 2020 82
Subtask 4
Dene
= ai
i
i
si 2
j 0
The forward direction is clear. We will justify the backward direction. For simplicity, assume
i
ai 1 ai 2 ... ak 1 0. Since y 2 is good, consider some way to pack them,
remove these biscuits from our collection.
i
We need to pack the remaining biscuits into x packs of 2 each. We do so by merging smaller
biscuits into bigger ones- whenever there are two biscuits of tastiness 2 for some j $ i, we replace
j
j 1
them with a single biscuit of tastiness 2 . It can be shown that we will end up with at least x
i
biscuits of tastiness 2 each after the merging.
We now have an ecient way to enumerate all the solutions. Let Ai be the set of good values
i
which are at most 2 . We then have
Ai1 Ai < ty ¶y 2
i
" Ai and si©x ' yz
We can now explicitly list out all elements of Ai . Thus the time taken for a single query is
linear in the size of the answer returned.
Subtask 5
Let g n be the number of possible y which are less than n. The following recurrence relation
solves the problem:
Let 2 $ n & 2 . Then
i i1
i i
g n g 2 g min n, 1 si©x 2
with the initial values g n 0 for all n & 0 and g 1 1.
2
By using a hash table to store all previously computed values, this algorithm runs in O k time.
0 1 2 i1
The time complexity is justied by the fact that once g 2 , g 2 , g 2 , ..., g 2 are
i
computed, we only need O k time to compute g 2 .
20 if(n<=0) return 0;
21 if(n==1) return 1;
22 if(m.find(n)!=m.end())
23 {
24 return m[n];
25 }
26 long long a = __lg(n-1);
27 return m[n] = f(s,x,1LL<<a) + f(s,x,min(n,1+s[a]/x)-(1LL<<a));
28 }
29
30 long long count_tastiness(long long x, std::vector<long long> a)
31 {
32 m.clear();
33 for(int i=1; i<(int)a.size(); i++)
34 {
35 a[i] = a[i-1] + (a[i]<<i);
36 }
37
38 while(a.size()<=60) a.push_back(a.back());
39 return f(a, x, 1+a.back());
40 }
41
42 // ---------------------------------------------------
43
44 int main()
45 {
46 std::clock_t c_start = std::clock();
47 auto t_start = std::chrono::high_resolution_clock::now();
48
49 auto t1 = clock();
50
51 std::freopen("../tests/5-11.in", "r", stdin) ;
52 std::freopen("biscuits.out", "w", stdout) ;
53
54 int q;
55 assert(scanf("%d", &q) == 1);
56 vector<int> k(q);
57 vector<long long> x(q);
58 vector<vector<long long>> a(q);
59 vector<long long> results(q);
60 for (int t = 0; t < q; t++)
61 {
62 assert(scanf("%d%lld", &k[t], &x[t]) == 2);
63 a[t] = vector<long long>(k[t]);
64 for (int i = 0; i < k[t]; i++)
65 {
66 assert(scanf("%lld", &a[t][i]) == 1);
67 }
68 }
69 fclose(stdin);
70
71 auto t2 = clock();
72
73 for (int t = 0; t < q; t++)
74 {
75 results[t] = count_tastiness(x[t], a[t]);
76 }
77
78 auto t3 = clock();
79
80 for (int t = 0; t < q; t++)
81 {
82 printf("%lld\n", results[t]);
83 }
84 fclose(stdout);
85
86 auto t4 = clock();
87
88 std::clock_t c_end = std::clock();
89 auto t_end = std::chrono::high_resolution_clock::now();
90
91 // reset console output
92 freopen("CON", "w", stdout);
93
94 //std::cout <<result<<’\n’<<’\n’;
95 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
CAPITOLUL 1. IOI 2020 84
3
4 #include <bits/stdc++.h>
5 #include "biscuits.h"
6
7 using namespace std;
8
9 #define debug(...) fprintf(stderr, __VA_ARGS__), fflush(stderr)
10
11 typedef long long lld;
12
13 lld count_tastiness(lld x, vector<lld> a)
14 {
15 vector <lld> status(63, 0);
16 lld sum = 0;
17 for (int i=0;i<63;i++)
18 {
19 if (i < a.size()) sum += a[i]<<i;
20 status[i] = sum;
21 }
22
23 vector <lld> dp(63, 0);
24 dp[0] = 1;
25 for (int i=1;i<63;i++)
26 {
27 lld cur = sum; dp[i] = 1;
28 for (int j=i;j--;)
29 {
30 cur = min(cur, status[j]);
31 if (x <= cur>>j)
32 {
33 cur -= x<<j;
34 dp[i] += dp[j];
35 }
36 }
37 }
38
39 return dp.back();
40 }
41
42 // ---------------------------------------------------
43
44 int main()
45 {
46 std::clock_t c_start = std::clock();
47 auto t_start = std::chrono::high_resolution_clock::now();
48
49 auto t1 = clock();
50
51 std::freopen("../tests/5-11.in", "r", stdin) ;
52 std::freopen("biscuits.out", "w", stdout) ;
53
54 int q;
55 assert(scanf("%d", &q) == 1);
56 vector<int> k(q);
57 vector<long long> x(q);
58 vector<vector<long long>> a(q);
59 vector<long long> results(q);
60 for (int t = 0; t < q; t++)
61 {
62 assert(scanf("%d%lld", &k[t], &x[t]) == 2);
63 a[t] = vector<long long>(k[t]);
64 for (int i = 0; i < k[t]; i++)
65 {
66 assert(scanf("%lld", &a[t][i]) == 1);
67 }
68 }
69 fclose(stdin);
70
71 auto t2 = clock();
72
73 for (int t = 0; t < q; t++)
74 {
75 results[t] = count_tastiness(x[t], a[t]);
76 }
77
78 auto t3 = clock();
CAPITOLUL 1. IOI 2020 86
79
80 for (int t = 0; t < q; t++)
81 {
82 printf("%lld\n", results[t]);
83 }
84 fclose(stdout);
85
86 auto t4 = clock();
87
88 std::clock_t c_end = std::clock();
89 auto t_end = std::chrono::high_resolution_clock::now();
90
91 // reset console output
92 freopen("CON", "w", stdout);
93
94 //std::cout <<result<<’\n’<<’\n’;
95 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
96 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
97 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
98
99 std::cout << std::fixed << std::setprecision(2)
100 << "\nCPU time used: "
101 << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"
102 << "Wall clock time passed: "
103 << std::chrono::duration<double, std::milli>(t_end-t_start).count()
104 << " ms\n";
105
106 return 0;
107 }
108 /*
109 t2-t1 = 0.1
110 t3-t2 = 0.07
111 t4-t3 = 0.015
112
113 CPU time used: 185.00 ms
114 Wall clock time passed: 185.02 ms
115
116 Process returned 0 (0x0) execution time : 0.248 s
117 Press any key to continue.
118 */
33 if(T == 1) return 1 + p;
34 int i = 63 - __builtin_clzll(T);
35 return c[i - 1] + min(r[i] + 1, get_r(T - (1LL << i)));
36 }
37
38 long long count_tastiness(long long x, vector<ll> s)
39 {
40 //int k = s.size();
41 s.resize(maxk);
42 for(int i = 1; i <= 60; ++i) s[i] = s[i - 1] + (1LL << i) * s[i];
43
44 p = (s[0] >= x);
45 r[0] = p - 1;
46 c[0] = p + 1;
47
48 for(int i = 1; i <= 60; ++i)
49 {
50 ll T = s[i] / x - (1LL << i);
51 if(T < 0) r[i] = -1;
52 else
53 {
54 if((1LL << i) - 1 <= T) r[i] = c[i - 1] - 1;
55 else r[i] = get_r(T) - 1;
56 }
57
58 c[i] = c[i - 1] + r[i] + 1;
59 }
60
61 return c[60];
62 }
63
64 // ---------------------------------------------------
65
66 int main()
67 {
68 std::clock_t c_start = std::clock();
69 auto t_start = std::chrono::high_resolution_clock::now();
70
71 auto t1 = clock();
72
73 std::freopen("../tests/5-11.in", "r", stdin) ;
74 std::freopen("biscuits.out", "w", stdout) ;
75
76 int q;
77 assert(scanf("%d", &q) == 1);
78 vector<int> k(q);
79 vector<long long> x(q);
80 vector<vector<long long>> a(q);
81 vector<long long> results(q);
82 for (int t = 0; t < q; t++)
83 {
84 assert(scanf("%d%lld", &k[t], &x[t]) == 2);
85 a[t] = vector<long long>(k[t]);
86 for (int i = 0; i < k[t]; i++)
87 {
88 assert(scanf("%lld", &a[t][i]) == 1);
89 }
90 }
91 fclose(stdin);
92
93 auto t2 = clock();
94
95 for (int t = 0; t < q; t++)
96 {
97 results[t] = count_tastiness(x[t], a[t]);
98 }
99
100 auto t3 = clock();
101
102 for (int t = 0; t < q; t++)
103 {
104 printf("%lld\n", results[t]);
105 }
106 fclose(stdout);
107
108 auto t4 = clock();
CAPITOLUL 1. IOI 2020 88
109
110 std::clock_t c_end = std::clock();
111 auto t_end = std::chrono::high_resolution_clock::now();
112
113 // reset console output
114 freopen("CON", "w", stdout);
115
116 //std::cout <<result<<’\n’<<’\n’;
117 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
118 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
119 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
120
121 std::cout << std::fixed << std::setprecision(2)
122 << "\nCPU time used: "
123 << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"
124 << "Wall clock time passed: "
125 << std::chrono::duration<double, std::milli>(t_end-t_start).count()
126 << " ms\n";
127
128 return 0;
129 }
130 /*
131 t2-t1 = 0.116
132 t3-t2 = 0.016
133 t4-t3 = 0.015
134
135 CPU time used: 147.00 ms
136 Wall clock time passed: 147.20 ms
137
138 Process returned 0 (0x0) execution time : 0.201 s
139 Press any key to continue.
140 */
41 // ---------------------------------------------------
42
43 int main()
44 {
45 std::clock_t c_start = std::clock();
46 auto t_start = std::chrono::high_resolution_clock::now();
47
48 auto t1 = clock();
49
50 std::freopen("../tests/5-11.in", "r", stdin) ;
51 std::freopen("biscuits.out", "w", stdout) ;
52
53 int q;
54 assert(scanf("%d", &q) == 1);
55 vector<int> k(q);
56 vector<long long> x(q);
57 vector<vector<long long>> a(q);
58 vector<long long> results(q);
59 for (int t = 0; t < q; t++)
60 {
61 assert(scanf("%d%lld", &k[t], &x[t]) == 2);
62 a[t] = vector<long long>(k[t]);
63 for (int i = 0; i < k[t]; i++)
64 {
65 assert(scanf("%lld", &a[t][i]) == 1);
66 }
67 }
68 fclose(stdin);
69
70 auto t2 = clock();
71
72 for (int t = 0; t < q; t++)
73 {
74 results[t] = count_tastiness(x[t], a[t]);
75 }
76
77 auto t3 = clock();
78
79 for (int t = 0; t < q; t++)
80 {
81 printf("%lld\n", results[t]);
82 }
83 fclose(stdout);
84
85 auto t4 = clock();
86
87 std::clock_t c_end = std::clock();
88 auto t_end = std::chrono::high_resolution_clock::now();
89
90 // reset console output
91 freopen("CON", "w", stdout);
92
93 //std::cout <<result<<’\n’<<’\n’;
94 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
95 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
96 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
97
98 std::cout << std::fixed << std::setprecision(2)
99 << "\nCPU time used: "
100 << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"
101 << "Wall clock time passed: "
102 << std::chrono::duration<double, std::milli>(t_end-t_start).count()
103 << " ms\n";
104
105 return 0;
106 }
107 /*
108 t2-t1 = 0.123
109 t3-t2 = 0.078
110 t4-t3 = 0.022
111
112 CPU time used: 223.00 ms
113 Wall clock time passed: 222.80 ms
114
115 Process returned 0 (0x0) execution time : 0.270 s
116 Press any key to continue.
CAPITOLUL 1. IOI 2020 90
117 */
72 }
73
74 auto t3 = clock();
75
76 for (int t = 0; t < q; t++)
77 {
78 printf("%lld\n", results[t]);
79 }
80 fclose(stdout);
81
82 auto t4 = clock();
83
84 std::clock_t c_end = std::clock();
85 auto t_end = std::chrono::high_resolution_clock::now();
86
87 // reset console output
88 freopen("CON", "w", stdout);
89
90 //std::cout <<result<<’\n’<<’\n’;
91 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
92 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
93 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
94
95 std::cout << std::fixed << std::setprecision(2)
96 << "\nCPU time used: "
97 << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"
98 << "Wall clock time passed: "
99 << std::chrono::duration<double, std::milli>(t_end-t_start).count()
100 << " ms\n";
101
102 return 0;
103 }
104 /*
105 t2-t1 = 0.116
106 t3-t2 = 0.019
107 t4-t3 = 0.02
108
109 CPU time used: 155.00 ms
110 Wall clock time passed: 155.12 ms
111
112 Process returned 0 (0x0) execution time : 0.205 s
113 Press any key to continue.
114 */
1.5 mushrooms
Problema 5 - Counting Mushrooms 100 de puncte
Author: Angus Ritossa
Expertul în ciuperci Andrew investigheaz ciupercile native din Singapore.
Ca parte a cercet rii sale, Andrew culege n ciuperci marcate de la 0 la n 1. Fiecare ciuperc
aparµine uneia din cele dou specii numite A ³i B.
Andrew ³tie c ciuperca 0 aparµine speciei A, dar, pentru c cele dou specii arat la fel,
el nu cunoa³te speciile ciupercilor de la 1 la n 1.
Din fericire, Andrew are o ma³in în laborator care îl poate ajuta cu asta. Pentru a folosi
aceast ma³in , trebuie plasate dou sau mai multe ciuperci în linie în interiorul ma³inii ³i apoi
pornit ma³ina. Apoi, ma³ina calculeaz num rul perechilor adiacente de ciuperci ce sunt din
specii diferite. De exemplu, dac punem ciuperci din speciile [A,B,B,A] (în aceast ordine) în
ma³in , rezultatul va 2.
Totu³i, pentru c operarea ma³inii este foarte scump , ma³ina poate folosit pentru un num r
limitat de teste. în plus, num rul total de ciuperci amplasate în ma³in cumulat pentru toate
testele nu poate dep ³i 100 000. Folosiµi aceast ma³in pentru a-l ajuta pe Andrew s numere
ciupercile adunate din specia A.
CAPITOLUL 1. IOI 2020 92
Detalii de implementare
Trebuie s implementaµi urm toarea funcµie:
int count_mushrooms(int n)
int use_machine(int[] x)
Exemple
Exemplul 1 Consider m un scenariu în care avem 3 ciuperci din speciile [A,B,B], în aceast
ordine. Funcµia count_mushrooms este apelat astfel:
count_mushrooms(3)
Aceast funcµie poate apela use_machine([0, 1, 2]), care (în acest scenariu) returneaz 1.
Mai apoi, ar putea apela use_machine([2, 1]), care returneaz 0.
În acest moment, sunt suciente informaµii pentru a trage concluzia c exist o singur ciuperc
din specia A. Astfel, funcµia count_mushrooms ar trebui s returneze 1.
Exemplul 2 Consider m cazul în care avem 4 ciuperci din speciile [A,B,A,A], în aceast ordine.
Funcµia count_mushrooms este apelat astfel:
count_mushrooms(4)
Funcµia poate apela use_machine([0, 2, 1, 3]), care returneaz 2. Poate apoi apela
use_machine([1, 2]), care returneaz 1.
În acest moment, sunt suciente informaµii pentru a trage concluzia c exist 3 ciuperci din
specia A.
Astfel, funcµia count_mushrooms ar trebui s returneze 3.
Restricµii
2 & n & 20 000
Punctare
În toate testele, dac apelurile funcµiei use_machine nu sunt conform regulilor de mai sus,
sau valoarea returnat de count_mushrooms este incorect , scorul soluµiei va 0. Altfel, e Q
num rul maxim de apeluri al funcµiei use_machine. Atunci, scorul va calculat dup urm torul
tabel:
Condiµie Scor
20 000 $ Q 0
10 010 $ Q & 20 000 10
904 $ Q & 10 010 25
226 $ Q & 904 226
Q
100
Q & 226 100
CAPITOLUL 1. IOI 2020 93
Pentru unele cazuri comportamentul graderului este adaptiv. Asta înseamn c pentru aceste
teste graderul nu are o secvenµ x a speciilor de ciuperci. în schimb, r spunsul dat de grader
poate depinde de apelurile anterioare ale funcµiei use_machine.
Totu³i, se garanteaz c r spunsul graderului este astfel încât dup ecare interacµiune exist
cel puµin o secvenµ de ciuperci consistent cu toate r spunsurile date pân acum.
Sample grader
Sample graderul cite³te un vector de întregi s reprezentând speciile de ciuperci. Pentru toate
valorile 0 & i & n 1, si 0 înseamn c specia ciupercii i este A, iar si 1 înseamn c
specia ciupercii i este B. Graderul cite³te în urm torul format:
line 1: n
line 2: s0 s1 ... sn 1
10 points
For each 1 & i & n 1, query use_machine([0,i]). We can thus determine the species of
every mushroom.
25 points
Same idea as above, except that we query use_machine([i, 0, i+1]) for all odd values of
i. As we only query odd values, the number of queries required is halved.
Beyond 25 points
The general strategy is as follows:
Collect a set of k mushrooms which are known to be of the same species, let these mushrooms
be x1 , x2 , ..., xk .
We can now make a query of the form y1 , x1 , y2 , x2 , ..., yk , xk . The return value to this
query reveals the number of type A mushrooms among y1 , y2 , ..., yk .
A possible strategy is to query 0, i for each 1 & i & 2 k 2, thus determining the species of
the rst 2k 1 mushrooms. We can then nd k mushrooms of the same type. The total number
of queries is given by 2k 2 * n 2k 1©k 0. Optimizing over possible values of k gives 397
queries, achieved when 94 & k & 107.
It is possible to further reduce the number of queries to k * n 2k 1©k 0. We rst query
0, 1 and 0, 2. This gives us two types of mushrooms of the same species, call it x, y .
We can proceed by querying 3, x, 4, y . The return value of this function will identify the
species of both mushroom 3 and 4.
Using this approach, we can now nd the species of the rst 2k 2 mushrooms with only k
queries. By setting to any value between 137 and 146, we use at most 281 queries.
Finally, observe that when we query y1 , x1 , y2 , x2 , ...yk , xk , we gain information about the
species of y1 by looking at the parity of the return value.
Thus, we can repeatedly expand our set of known mushrooms and increase the value of k
appropriately, using at most 245 queries when 73 & k & 94.
CAPITOLUL 1. IOI 2020 94
100 points
Full solution identies about 5 mushrooms in 2 queries during the rst phase. There are con-
structive appoaches, but we can also try to brute-force all possible strategies that can achieve
this.
Suppose that we need to identify mushrooms A, B, C, D, E, and we have already identied x
and y mushrooms of types 0 and 1 respectively. We can try all possible strings of characters A,
B, C, D, E, 0 (x times), 1 (y times) to ask as a rst query q1 .
Depending on the answer to q1 , the second query q2 should be able to unambiguously determine
each type of A, B, C, D, E, so we can brute-force it as well (note that q2 may depend on the result
of q1 ).
The number of possible queries is small enough so that all decision trees can be processed
within reasonable time.
To avoid overhead for identifying the rst few mushrooms, we can actually have two decision
trees:
The rst tree uses the only additional mushroom of type 0, and will either gure out that
A, B, C, D, E are all type 0 in 1 query, or identify them in 3 queries.
The second tree uses, when available, 3 mushrooms of type 0 and 1 mushroom of type 1 (or
vice versa). It always identies A, B, C, D, E in 5 queries.
We will employ the second tree whenever there are enough extra mushrooms, and the rst
one otherwise (that only happens when all identied mushrooms are type 0). This approach can
unconditionally identify 5k mushrooms in 2k 1 queries. Combining this with ideas above and
choosing k optimally, we can solve the problem in 226 queries.
Note that there is a much simpler randomized solution that also identies 2.5 mushrooms
per query, but it can't be used because of adaptive grading (unless you can somehow confuse the
grader ...).
Short statement: there are N & 20 000 objects with value 0 or 1. Each time you can select
some objects and permute them to form a 0-1 sequence, then the interactor will tell you the total
number of 0-1 and 1-0 shifts in the sequence (i.e. 011000 has 2 shifts and 000101 has 3 shifts).
It is guaranteed that the value of the 1st object is 0. You are required to nd out the number of
objects with value 0 within 226 queries (100%) / 904 queries (>25%), and the total length of the
5
sequence in the queries is bounded by 10 .
When encountering the problem, a linear algorithm comes directly. We can check whether
there is a shift in value sequence 0, x . If so x 1, otherwise x 0. Hence we can solve the
problem within N queries, getting 10% as a result.
We then can come up to do some tiny optimizations, without changing the linearity of the
algorithm. After two queries, we will have at least two 0 s or 1 s. Then we can set the value
sequence to be x, 0, y, 0 or x, 1, y, 1, then the value of x and y can be determined simultaneously.
This lead to an approach with N2 1 queries which gets 25%.
For higher points, we need a sublinear algorithm. As we only need the sum of the values of
objects, we don't have to determine the value of each object. One observation is that we can
take advantage of the objects we have determined, and infer the sum of values by asking for
a, X, b, X, c, X, d, X, ..., X where X 0 or 1 depending on which kind of object we have more (so
that the sequence can contain more unseen objects for counting).
CAPITOLUL 1. IOI 2020 95
However, one should notice that putting more than one value between X or replacing X with
both 1 and 0 seems useless. The former is just why we need pattern like a, X, b, X, ..., and the
latter is because of, if we get variable p q , we are required to perform another query to solve p
and q , then why not ask p and q individually. This may make us confused about how to optimize
the algorithm.
In fact, there is still an easy optimization of the current algorithm. We can divide the program
into two phases: in the rst phase, we use patterns like x, 0, y, 0, and determine two variables at
a time; in the second phase, we use the determined variables to do queries. BalancingÓ
the two
phases (seems 3:4 in number of queries) gives 244 queries as a result (about 1.75 n according to
calculation), which gets 92.62%.
We will reformulate the statement (which is stronger) according to our discussion above. We
can hold a value k on our hand, initially k 1. Then in each step, you can ask for the sum of no
more than *k ©20 objects. Once you know the value of some specic object, we can increase k by
one; and after each step, k will automatically increase one. Our target is to determine the sum
of all objects. Then our two-phase algorithm is just to ask one object in the rst phase, and as
many objects as possible in the second phase.
Intuitively, the bottleneck of our algorithm seems to be that only ask for one object at a time,
which only utilizes 1 bits of information. This still seems hard to optimize, but if you once met
another problem before, it will be easier for you to solve this problem. The target of that problem
is to recover a 0-1 sequence of length n withinO n© log n steps by asking the sum of some elements
(for example, n 1000 and solve it in 300 steps).
The solution of that problem is a divide-and-conquer like approach. Let fm be the longest
m
sequence we can recover within 2 steps, and qm be the query sequence of it, with the last step
asking for the sum of the whole sequence, then we can have fm1 ' 2fm 2 1. This is done
m
m
by dividing the sequence into two blocks of size fm and one block of size 2 1. Then we rst
ask for the total number of ones c in the second block of size fm . For each non-last query qm,i
in qm , if we apply it on the two fm blocks, we will get a and b respectively. We construct two
queries, asking for a b and a c b i, where i is a bit in the last block, then clearly we can
recover a, b, i through the query. The last query is used to obtain the total number of ones in the
sequence. We recursively apply this approach, and nally, we are done with O n© log n steps.
m
Thus in the rst phase of our algorithm, we can try to use a bunch of 2 queries to obtain fm
determined objects if we have enough determined objects for calculating the sum. We can sort
the required bits in qm and get the required initial bits, then do a DP on the number of queries
(we take the addition on k in each step into consideration). Finally, we enumerate a position to
begin the second phase. This yields 209 queries in total, which is much smaller than the bound
given in the problem. A tiny optimization reducing the number of ones required in the last query
of qm further enables us to solve the problem in 203 queries.
The implementation of this approach can be found here:
https://loj.ac/submission/938329
8 #include <vector>
9 #include <string>
10 #include <map>
11 #include <cassert>
12
13 // -------------------------------------------------------------
14
15 #include <cstdio>
16 #include <cstdlib>
17 #include <cstdarg>
18
19 #include <iostream> /* cout */
20 #include <iomanip> /* setprecision */
21 #include <chrono> /* chrono */
22
23 // -------------------------------------------------------------
24
25 #define mp make_pair
26 #define mt make_tuple
27 #define fi first
28 #define se second
29 #define pb push_back
30 #define all(x) (x).begin(), (x).end()
31 #define rall(x) (x).rbegin(), (x).rend()
32 #define forn(i, n) for (int i = 0; i < (int)(n); ++i)
33 #define for1(i, n) for (int i = 1; i <= (int)(n); ++i)
34 #define ford(i, n) for (int i = (int)(n) - 1; i >= 0; --i)
35 #define fore(i, a, b) for (int i = (int)(a); i <= (int)(b); ++i)
36
37 using namespace std;
38
39 typedef pair<int, int> pii;
40 typedef vector<int> vi;
41 typedef vector<pii> vpi;
42 typedef vector<vi> vvi;
43 typedef long long i64;
44 typedef vector<i64> vi64;
45 typedef vector<vi64> vvi64;
46 typedef pair<i64, i64> pi64;
47 typedef double ld;
48
49 template<class T> bool uin(T &a, T b) {return a > b ? (a = b, true) : false;}
50 template<class T> bool uax(T &a, T b) {return a < b ? (a = b, true) : false;}
51
52 vi labels;
53 vvi lst;
54 int K = 110;
55
56 int ans;
57
58 void label(int p, int z)
59 {
60 // cerr << p << ’ ’ << z << ’\n’;
61 labels[p] = z;
62 lst[z].pb(p);
63 if (!z) ++ans;
64 }
65
66 int p;
67 int z;
68 vi toQ;
69
70 string subs(string s, int mask)
71 {
72 for (char &c: s)
73 if (c >= ’A’ && c <= ’Z’)
74 c = (char)(’0’ + ((mask >> (c - ’A’)) & 1));
75 return s;
76 }
77
78 int eval(const string &s)
79 {
80 int ret = 0;
81 forn(i, (int)s.size() - 1) ret += int(s[i] != s[i + 1]);
82 return ret;
83 }
CAPITOLUL 1. IOI 2020 97
84
85 int query(string s)
86 {
87 vi v;
88 vi ptr(2);
89 for (char c: s)
90 {
91 if (c == ’0’ || c == ’1’)
92 {
93 int d = (c - ’0’) ^ z;
94 assert(ptr[d] < (int)lst[d].size());
95 v.pb(lst[d][ptr[d]++]);
96 }
97 else
98 {
99 int l = c - ’A’;
100 v.pb(toQ[l]);
101 }
102 }
103
104 return use_machine(v);
105 }
106
107 map<vi, string> prec1 =
108 {
109 {{}, "A0B0C0DE"},
110 {{1}, "CED"},
111 {{2}, "DBE0A"},
112 {{3}, "CB0E0DA1"},
113 {{4}, "D0A0E0CB1"},
114 {{5}, "DBCE1"},
115 {{6}, "CED"}
116 };
117
118 map<vi, string> prec2 =
119 {
120 {{}, "ABCDE0"},
121 {{1}, "B0"},
122 {{1, 1}, "EADC"},
123 {{2}, "CB0D"},
124 {{2, 1}, "EADB"},
125 {{2, 2}, "DAE0CB"},
126 {{3}, "CB0D"},
127 {{3, 1}, "EDB0"},
128 {{3, 2}, "AED"},
129 {{3, 3}, "ED"},
130 {{4}, "B0"},
131 {{4, 1}, "0EACD"}
132 };
133
134
135 void magic(map<vi, string> &m)
136 {
137 toQ.clear();
138 forn(i, 5) toQ.pb(p + i);
139 vi seq;
140 map<string, int> res;
141 while (m.count(seq))
142 {
143 string s = m[seq];
144 int x = query(s);
145 res[s] = x;
146 seq.pb(x);
147 }
148
149 vi goodM;
150 forn(mask, 32)
151 {
152 bool ok = true;
153 for (auto w: res) ok &= eval(subs(w.fi, mask)) == w.se;
154 if (ok) goodM.pb(mask);
155 }
156
157 assert(goodM.size() == 1);
158 int mask = goodM[0];
159 forn(i, 5) label(p++, ((mask >> i) & 1) ^ z);
CAPITOLUL 1. IOI 2020 98
160 }
161
162 int count_mushrooms(int n)
163 {
164 labels = vi(n, -1);
165 lst = vvi(2);
166 p = 1;
167 ans = 0;
168 label(0, 0);
169 while (p < n)
170 {
171 z = lst[0].size() > lst[1].size() ? 0 : 1;
172 if (n - p < 5 || (int)lst[z].size() >= K)
173 {
174 vi m;
175 int i = 0;
176 while (p < n && i < (int)lst[z].size())
177 {
178 m.pb(p++);
179 m.pb(lst[z][i++]);
180 }
181 int x = use_machine(m);
182 lst[z ^ (x & 1)].pb(m[0]);
183 x = (x + 1) / 2;
184 ans += (z ? x : i - x);
185 }
186 else
187 magic(!lst[z ^ 1].empty() && lst[z].size() >= 3 ? prec1 : prec2);
188 }
189
190 return ans;
191 }
192
193 // ----------------------------------------------------------
194
195 static char fmt_buffer[100000];
196 #define FMT_TO_STR(fmt, result) va_list vargs; va_start(vargs, fmt); \
197 vsnprintf(fmt_buffer, sizeof(fmt_buffer), fmt, vargs); \
198 va_end(vargs); fmt_buffer[sizeof(fmt_buffer)-1] = 0; \
199 std::string result(fmt_buffer);
200
201 static const int min_n = 2;
202 static const int max_n = 20000;
203 static const int max_qc = 20000;
204 static const int max_qs = 100000;
205 static const int species_A = 0;
206 static const int species_B = 1;
207
208 static int n;
209 static std::vector<int> species;
210 static int qc, qs;
211
212 static inline void error_if(bool cond, std::string message)
213 {
214 if (cond)
215 {
216 printf("%s\n", message.c_str());
217 exit(0);
218 }
219 }
220
221 static inline void wrong_if(bool cond, std::string message)
222 {
223 error_if(cond, "Wrong Answer: "+message);
224 }
225
226 int use_machine(std::vector<int> x)
227 {
228 const int xs = x.size();
229 wrong_if(xs < 2, "Too small array for query.");
230 wrong_if(xs > n, "Too large array for query.");
231 qc++;
232 wrong_if(qc > max_qc, "Too many queries.");
233 qs += xs;
234 wrong_if(qs > max_qs, "Too many total array sizes as queries.");
235 for (int i = 0; i < xs; i++)
CAPITOLUL 1. IOI 2020 99
236 wrong_if(x[i] < 0 || n-1 < x[i], "Invalid value in the query array.");
237
238 std::vector<bool> used(n, false);
239 for (int i = 0; i < xs; i++)
240 {
241 wrong_if(used[x[i]], "Duplicate value in the query array.");
242 used[x[i]] = true;
243 }
244
245 int diffs = 0;
246 for (int i = 1; i < xs; i++)
247 diffs += int(species[x[i]] != species[x[i-1]]);
248 return diffs;
249 }
250
251 #ifdef __GNUC__
252 __attribute__ ((format(printf, 2, 3)))
253 #endif
254
255 static inline void check_input(bool cond, const char* message_fmt, ...)
256 {
257 FMT_TO_STR(message_fmt, message);
258 error_if(!cond, "Invalid input: "+message);
259 }
260
261 int main()
262 {
263 std::clock_t c_start = std::clock();
264 auto t_start = std::chrono::high_resolution_clock::now();
265
266 auto t1 = clock();
267
268 //std::freopen("../tests/n5-16.in", "r", stdin);
269 std::freopen("../tests/1-09.in", "r", stdin);// 1-05 ... 1-11
270 //std::freopen("mushrooms.out", "w", stdout);
271
272 string strategy;
273 std::getline (std::cin,strategy);
274 //cout<<"strategy = "<<strategy<<"\n";
275
276 check_input(1 == scanf("%d", &n),
277 "Could not read n.");
278 check_input(min_n <= n,
279 "n must not be less than %d, but it is %d.", min_n, n);
280 check_input(n <= max_n,
281 "n must not be greater than %d, but it is %d.", max_n, n);
282
283 species.resize(n);
284 for (int i = 0; i < n; i++)
285 {
286 check_input(1 == scanf("%d",
287 &species[i]),
288 "Could not read species element [%d].", i);
289 check_input(species[i]==species_A || species[i] == species_B,
290 "Species elements must be %d or %d, \
291 but species element [%d] is %d.",
292 species_A, species_B, i, species[i]);
293 }
294
295 check_input(species[0] == species_A,
296 "Species element [%d] must be %d.", 0, species_A);
297 // Postponed closing standard input in order to allow \
298 interactive usage of the grader.
299
300 auto t2 = clock();
301
302 qc = 0;
303 qs = 0;
304 int answer = count_mushrooms(n);
305
306 auto t3 = clock();
307
308 printf("%d\n%d\n", answer, qc);
309
310 fclose(stdout);
311 fclose(stdin);
CAPITOLUL 1. IOI 2020 100
312
313 auto t4 = clock();
314
315 std::clock_t c_end = std::clock();
316 auto t_end = std::chrono::high_resolution_clock::now();
317
318 // reset console output
319 freopen("CON", "w", stdout);
320
321 std::cout<<"answer = "<<answer<<"\n";
322 std::cout<<"qc = "<<qc<<"\n\n";
323
324 //std::cout <<result<<’\n’<<’\n’;
325 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
326 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
327 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
328
329 std::cout << std::fixed << std::setprecision(2)
330 << "\nCPU time used: "
331 << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"
332 << "Wall clock time passed: "
333 << std::chrono::duration<double, std::milli>(t_end-t_start).count()
334 << " ms\n";
335
336 return 0;
337 }
338 /*
339 answer = 10124
340 qc = 216
341
342 t2-t1 = 0.085
343 t3-t2 = 0.074
344 t4-t3 = 0.002
345
346 CPU time used: 161.00 ms
347 Wall clock time passed: 160.62 ms
348
349 Process returned 0 (0x0) execution time : 0.200 s
350 Press any key to continue..
351 */
33 }
34
35 int calc(string s, int x)
36 {
37 for (int i = 0; i < int(s.length()); ++i)
38 {
39 if (’0’ <= s[i] && s[i] <= ’9’)
40 {
41 s[i] = ’A’ + ((x >> s[i] - ’0’) & 1);
42 }
43 }
44
45 int ret = 0;
46 for (int i = 1; i < int(s.length()); ++i)
47 {
48 ret += s[i - 1] != s[i];
49 }
50
51 return ret;
52 }
53
54 int count_mushrooms(int n)
55 {
56 const string start = "0A1A2A3A4";
57 string qu[9];
58 qu[0] = "01234A"; // (1, 0)
59 qu[1] = "01234A"; // (1, 0)
60 qu[2] = "012B3B4A"; // (1, 2)
61 qu[3] = "0124AAB3B"; // (2, 2)
62 qu[4] = "014A23BA"; // (2, 1)
63 qu[5] = "0124A3A"; // (2, 0)
64 qu[6] = "012A3A4A"; // (3, 0)
65 qu[7] = "01234A"; // (1, 0)
66 qu[8] = "01234A"; // (1, 0)
67
68 const int B = 100;
69 vector<int> A[2];
70 A[0].push_back(0);
71 int i = 1;
72 for (; i < n && int(max(A[0].size(), A[1].size())) < 2; ++i)
73 {
74 A[use_machine({ 0, i })].push_back(i);
75 }
76
77 for (; i + 1 < n && int(max(A[0].size(), A[1].size())) < B; )
78 {
79 if (i + 4 < n &&
80 int(max(A[0].size(), A[1].size())) >= 4 &&
81 int(min(A[0].size(), A[1].size())) >= 2)
82 {
83 vector<int> X;
84 while (int(X.size()) < 5) X.push_back(i++);
85
86 int b = A[0].size() > A[1].size() ? 0 : 1;
87 int ret1 = ask(start, X, A[b], A[1 - b]);
88 int ret2 = ask(qu[ret1], X, A[b], A[1 - b]);
89 int bit;
90
91 for (bit = 0;
92 calc(start, bit) != ret1 || calc(qu[ret1], bit) != ret2;
93 ++bit);
94
95 if (b) bit = 31 - bit;
96 for (int i = 0; i < 5; ++i)
97 {
98 A[(bit >> i) & 1].push_back(X[i]);
99 }
100 }
101 else if (int(A[0].size()) >= 2)
102 {
103 int ret = use_machine({ A[0][0], i, A[0][1], i + 1 });
104 A[ret % 2].push_back(i + 1);
105 A[ret / 2].push_back(i);
106 i += 2;
107 }
108 else
CAPITOLUL 1. IOI 2020 102
109 {
110 int ret = use_machine({ A[1][0], i, A[1][1], i + 1 });
111 A[1 - ret % 2].push_back(i + 1);
112 A[1 - ret / 2].push_back(i);
113 i += 2;
114 }
115 }
116
117 int ret = A[0].size();
118 for (; i < n; )
119 {
120 if (A[0].size() > A[1].size())
121 {
122 vector<int> q1;
123 for (; i < n && q1.size() < A[0].size(); ++i)
124 q1.push_back(i);
125
126 vector<int> q;
127 for (int i = 0; i < int(q1.size()); ++i)
128 {
129 q.push_back(A[0][i]);
130 q.push_back(q1[i]);
131 }
132
133 int u = use_machine(q);
134 A[u % 2].push_back(q1.back());
135 ret += int(q1.size()) - (u + 1) / 2;
136 }
137 else
138 {
139 vector<int> q1;
140 for (; i < n && q1.size() < A[1].size(); ++i)
141 q1.push_back(i);
142
143 vector<int> q;
144 for (int i = 0; i < int(q1.size()); ++i)
145 {
146 q.push_back(A[1][i]);
147 q.push_back(q1[i]);
148 }
149
150 int u = use_machine(q);
151 A[1 - u % 2].push_back(q1.back());
152 ret += (u + 1) / 2;
153 }
154 }
155
156 return ret;
157 }
158
159 // ----------------------------------------------------------
160
161 static char fmt_buffer[100000];
162 #define FMT_TO_STR(fmt, result) va_list vargs; va_start(vargs, fmt); \
163 vsnprintf(fmt_buffer, sizeof(fmt_buffer), fmt, vargs); \
164 va_end(vargs); fmt_buffer[sizeof(fmt_buffer)-1] = 0; \
165 std::string result(fmt_buffer);
166
167 static const int min_n = 2;
168 static const int max_n = 20000;
169 static const int max_qc = 20000;
170 static const int max_qs = 100000;
171 static const int species_A = 0;
172 static const int species_B = 1;
173
174 static int n;
175 static std::vector<int> species;
176 static int qc, qs;
177
178 static inline void error_if(bool cond, std::string message)
179 {
180 if (cond)
181 {
182 printf("%s\n", message.c_str());
183 exit(0);
184 }
CAPITOLUL 1. IOI 2020 103
185 }
186
187 static inline void wrong_if(bool cond, std::string message)
188 {
189 error_if(cond, "Wrong Answer: "+message);
190 }
191
192 int use_machine(std::vector<int> x)
193 {
194 const int xs = x.size();
195 wrong_if(xs < 2, "Too small array for query.");
196 wrong_if(xs > n, "Too large array for query.");
197 qc++;
198 wrong_if(qc > max_qc, "Too many queries.");
199 qs += xs;
200 wrong_if(qs > max_qs, "Too many total array sizes as queries.");
201 for (int i = 0; i < xs; i++)
202 wrong_if(x[i] < 0 || n-1 < x[i], "Invalid value in the query array.");
203
204 std::vector<bool> used(n, false);
205 for (int i = 0; i < xs; i++)
206 {
207 wrong_if(used[x[i]], "Duplicate value in the query array.");
208 used[x[i]] = true;
209 }
210
211 int diffs = 0;
212 for (int i = 1; i < xs; i++)
213 diffs += int(species[x[i]] != species[x[i-1]]);
214 return diffs;
215 }
216
217 #ifdef __GNUC__
218 __attribute__ ((format(printf, 2, 3)))
219 #endif
220
221 static inline void check_input(bool cond, const char* message_fmt, ...)
222 {
223 FMT_TO_STR(message_fmt, message);
224 error_if(!cond, "Invalid input: "+message);
225 }
226
227 int main()
228 {
229 std::clock_t c_start = std::clock();
230 auto t_start = std::chrono::high_resolution_clock::now();
231
232 auto t1 = clock();
233
234 //std::freopen("../tests/n5-16.in", "r", stdin);
235 std::freopen("../tests/1-09.in", "r", stdin);// 1-05 ... 1-11
236 //std::freopen("mushrooms.out", "w", stdout);
237
238 string strategy;
239 std::getline (std::cin,strategy);
240 //cout<<"strategy = "<<strategy<<"\n";
241
242 check_input(1 == scanf("%d", &n),
243 "Could not read n.");
244 check_input(min_n <= n,
245 "n must not be less than %d, but it is %d.", min_n, n);
246 check_input(n <= max_n,
247 "n must not be greater than %d, but it is %d.", max_n, n);
248
249 species.resize(n);
250 for (int i = 0; i < n; i++)
251 {
252 check_input(1 == scanf("%d",
253 &species[i]),
254 "Could not read species element [%d].", i);
255 check_input(species[i]==species_A || species[i] == species_B,
256 "Species elements must be %d or %d, \
257 but species element [%d] is %d.",
258 species_A, species_B, i, species[i]);
259 }
260
CAPITOLUL 1. IOI 2020 104
15 {{}, "A0B0C0D1E"},
16 {{1}, "0D"},
17 {{2}, "0A0D0E"},
18 {{3}, "0A1BC0E0D"},
19 {{4}, "0A0E0BC1D"},
20 {{5}, "0A0BC1E0D"},
21 {{6}, "0A0D0E"},
22 {{7}, "0D"}
23 };
24
25 map <vector<int>, string> rule1_0_3 =
26 {
27 {{}, "0ABCDE"},
28 {{1}, "0ABCD"},
29 {{1, 1}, "AB0C"},
30 {{2}, "A0BCD"},
31 {{2, 1}, "AB0CE"},
32 {{2, 2}, "ABDC"},
33 {{2, 3}, "0C"},
34 {{3}, "A0BCE"},
35 {{3, 1}, "0B"},
36 {{3, 2}, "0BDC"},
37 {{3, 3}, "0D"},
38 {{3, 4}, "0D"},
39 {{4}, "A0BCD"},
40 {{4, 2}, "0C"},
41 {{4, 3}, "0ABCD"}
42 };
43
44 int eval(const string &choice, int msk, bool base)
45 {
46 int n = choice.length();
47 vector <bool> arr(n);
48 for (int i=0;i<n;i++)
49 {
50 if (choice[i] == ’0’) arr[i] = base;
51 else if (choice[i] == ’1’) arr[i] = base^1;
52 else arr[i] = msk>>(choice[i]-’A’)&1;
53 }
54
55 int ret = 0;
56 for (int i=1;i<n;i++) if (arr[i-1] != arr[i]) ret++;
57 return ret;
58 }
59
60 int count_mushrooms(int N)
61 {
62 int K = 97;
63 vector<int> arr[2] = {{0}, {}};
64 int pt = 1;
65
66 // Step 1: Check type of mushroom based on rule
67 while (N-pt >= 5 && max(arr[0].size(), arr[1].size()) < K)
68 {
69 int t = arr[1].size() > arr[0].size();
70 auto &rule = (
71 arr[t].size() >= 3 && arr[t^1].size() >= 1 ?
72 rule3_1_2 :
73 rule1_0_3
74 );
75
76 vector<int> path;
77 vector<bool> valid(32, 1);
78 while (rule.count(path))
79 {
80 string command = rule[path];
81 vector<int> test, p(2);
82 for (char c: command)
83 {
84 if (c == ’0’ || c == ’1’) test.push_back(arr[(c-’0’)^t][p[(c-’0’)^t]++])
;
85 else test.push_back(pt+(c-’A’));
86 }
87
88 int res = use_machine(test);
89 for (int i=0;i<32;i++) if (valid[i])
CAPITOLUL 1. IOI 2020 106
90 {
91 if (eval(command, i, t) != res) valid[i] = 0;
92 }
93
94 path.push_back(res);
95 }
96
97 int cnt = 0, msk;
98 for (int i=0;i<32;i++)
99 if (valid[i])
100 cnt++, msk = i;
101
102 assert(cnt == 1);
103
104 for (int i=0;i<5;i++)
105 arr[msk>>i&1].push_back(pt+i);
106
107 pt += 5;
108 }
109
110 // Step 2: Count number of type 0 mushrooms many by one
111 int zero_count = arr[0].size();
112 while (pt < N)
113 {
114 int t = arr[1].size() > arr[0].size();
115
116 vector<int> test;
117 for (int i=0;i<arr[t].size()&&pt+i<N;i++)
118 {
119 test.push_back(arr[t][i]);
120 test.push_back(pt+i);
121 }
122
123 int res = use_machine(test);
124 int cnt = res+1>>1;
125 if (!t) cnt = test.size()/2-cnt;
126 zero_count += cnt;
127 arr[res&1^t].push_back(test.back());
128 pt += test.size()/2;
129 }
130
131 return zero_count;
132 }
133
134 // ----------------------------------------------------------
135
136 static char fmt_buffer[100000];
137 #define FMT_TO_STR(fmt, result) va_list vargs; va_start(vargs, fmt); \
138 vsnprintf(fmt_buffer, sizeof(fmt_buffer), fmt, vargs); \
139 va_end(vargs); fmt_buffer[sizeof(fmt_buffer)-1] = 0; \
140 std::string result(fmt_buffer);
141
142 static const int min_n = 2;
143 static const int max_n = 20000;
144 static const int max_qc = 20000;
145 static const int max_qs = 100000;
146 static const int species_A = 0;
147 static const int species_B = 1;
148
149 static int n;
150 static std::vector<int> species;
151 static int qc, qs;
152
153 static inline void error_if(bool cond, std::string message)
154 {
155 if (cond)
156 {
157 printf("%s\n", message.c_str());
158 exit(0);
159 }
160 }
161
162 static inline void wrong_if(bool cond, std::string message)
163 {
164 error_if(cond, "Wrong Answer: "+message);
165 }
CAPITOLUL 1. IOI 2020 107
166
167 int use_machine(std::vector<int> x)
168 {
169 const int xs = x.size();
170 wrong_if(xs < 2, "Too small array for query.");
171 wrong_if(xs > n, "Too large array for query.");
172 qc++;
173 wrong_if(qc > max_qc, "Too many queries.");
174 qs += xs;
175 wrong_if(qs > max_qs, "Too many total array sizes as queries.");
176 for (int i = 0; i < xs; i++)
177 wrong_if(x[i] < 0 || n-1 < x[i], "Invalid value in the query array.");
178
179 std::vector<bool> used(n, false);
180 for (int i = 0; i < xs; i++)
181 {
182 wrong_if(used[x[i]], "Duplicate value in the query array.");
183 used[x[i]] = true;
184 }
185
186 int diffs = 0;
187 for (int i = 1; i < xs; i++)
188 diffs += int(species[x[i]] != species[x[i-1]]);
189 return diffs;
190 }
191
192 #ifdef __GNUC__
193 __attribute__ ((format(printf, 2, 3)))
194 #endif
195
196 static inline void check_input(bool cond, const char* message_fmt, ...)
197 {
198 FMT_TO_STR(message_fmt, message);
199 error_if(!cond, "Invalid input: "+message);
200 }
201
202 int main()
203 {
204 std::clock_t c_start = std::clock();
205 auto t_start = std::chrono::high_resolution_clock::now();
206
207 auto t1 = clock();
208
209 //std::freopen("../tests/n5-16.in", "r", stdin);
210 std::freopen("../tests/1-09.in", "r", stdin);// 1-05 ... 1-11
211 //std::freopen("mushrooms.out", "w", stdout);
212
213 string strategy;
214 std::getline (std::cin,strategy);
215 //cout<<"strategy = "<<strategy<<"\n";
216
217 check_input(1 == scanf("%d", &n),
218 "Could not read n.");
219 check_input(min_n <= n,
220 "n must not be less than %d, but it is %d.", min_n, n);
221 check_input(n <= max_n,
222 "n must not be greater than %d, but it is %d.", max_n, n);
223
224 species.resize(n);
225 for (int i = 0; i < n; i++)
226 {
227 check_input(1 == scanf("%d",
228 &species[i]),
229 "Could not read species element [%d].", i);
230 check_input(species[i]==species_A || species[i] == species_B,
231 "Species elements must be %d or %d, \
232 but species element [%d] is %d.",
233 species_A, species_B, i, species[i]);
234 }
235
236 check_input(species[0] == species_A,
237 "Species element [%d] must be %d.", 0, species_A);
238 // Postponed closing standard input in order to allow \
239 interactive usage of the grader.
240
241 auto t2 = clock();
CAPITOLUL 1. IOI 2020 108
242
243 qc = 0;
244 qs = 0;
245 int answer = count_mushrooms(n);
246
247 auto t3 = clock();
248
249 printf("%d\n%d\n", answer, qc);
250
251 fclose(stdout);
252 fclose(stdin);
253
254 auto t4 = clock();
255
256 std::clock_t c_end = std::clock();
257 auto t_end = std::chrono::high_resolution_clock::now();
258
259 // reset console output
260 freopen("CON", "w", stdout);
261
262 std::cout<<"answer = "<<answer<<"\n";
263 std::cout<<"qc = "<<qc<<"\n\n";
264
265 //std::cout <<result<<’\n’<<’\n’;
266 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
267 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
268 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
269
270 std::cout << std::fixed << std::setprecision(2)
271 << "\nCPU time used: "
272 << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"
273 << "Wall clock time passed: "
274 << std::chrono::duration<double, std::milli>(t_end-t_start).count()
275 << " ms\n";
276
277 return 0;
278 }
279
280 /*
281 answer = 10124
282 qc = 222
283
284 t2-t1 = 0.1
285 t3-t2 = 0.07
286 t4-t3 = 0
287
288 CPU time used: 170.00 ms
289 Wall clock time passed: 170.71 ms
290
291 Process returned 0 (0x0) execution time : 0.210 s
292 Press any key to continue.
293 */
325 {
326 check_input(1 == scanf("%d",
327 &species[i]),
328 "Could not read species element [%d].", i);
329 check_input(species[i]==species_A || species[i] == species_B,
330 "Species elements must be %d or %d, \
331 but species element [%d] is %d.",
332 species_A, species_B, i, species[i]);
333 }
334
335 check_input(species[0] == species_A,
336 "Species element [%d] must be %d.", 0, species_A);
337 // Postponed closing standard input in order to allow \
338 interactive usage of the grader.
339
340 auto t2 = clock();
341
342 qc = 0;
343 qs = 0;
344 int answer = count_mushrooms(n);
345
346 auto t3 = clock();
347
348 printf("%d\n%d\n", answer, qc);
349
350 fclose(stdout);
351 fclose(stdin);
352
353 auto t4 = clock();
354
355 std::clock_t c_end = std::clock();
356 auto t_end = std::chrono::high_resolution_clock::now();
357
358 // reset console output
359 freopen("CON", "w", stdout);
360
361 std::cout<<"answer = "<<answer<<"\n";
362 std::cout<<"qc = "<<qc<<"\n\n";
363
364 //std::cout <<result<<’\n’<<’\n’;
365 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
366 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
367 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
368
369 std::cout << std::fixed << std::setprecision(2)
370 << "\nCPU time used: "
371 << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"
372 << "Wall clock time passed: "
373 << std::chrono::duration<double, std::milli>(t_end-t_start).count()
374 << " ms\n";
375
376 return 0;
377 }
378 /*
379 answer = 10124
380 qc = 198
381
382 t2-t1 = 0.084
383 t3-t2 = 0.078
384 t4-t3 = 0
385
386 CPU time used: 162.00 ms
387 Wall clock time passed: 162.82 ms
388
389 Process returned 0 (0x0) execution time : 0.270 s
390 Press any key to continue.
391 */
CAPITOLUL 1. IOI 2020 114
1.6 stations
Problema 6 - Stations 100 de puncte
Author: Mikhail Tikhomirov
Singapore's Internet Backbone (SIB) const în n staµii, c rora li s-au atribuit indici între 0
³i n 1. De asemenea, exist n 1 leg turi bidirecµionale, numerotate de la 0 la n 2. Fiecare
leg tur conecteaz dou staµii distincte. Dou staµii conectate printr-o leg tur se numesc vecine.
Un drum de la staµia x la staµia y este o secvenµ de staµii distincte a0 , a1 , ..., ap , astfel încât
a 0 x, ap y ³i oricare dou staµii consecutive pe drum sunt vecine. Exist exact un drum
între oricare doua staµii distincte x ³i y .
Orice staµie x poate crea un pachet (de date) ³i s îl trimit c tre oricare alt staµie y , numit
destinaµia pachetului. Acest pachet trebuie rutat pe unicul drum de la x la y , dup cum urmeaz .
Fie z staµia ce deµine la momentul actual pachetul, a c rui staµie destinaµie este y (z neqy ).
În acest caz staµia z :
1. Execut o procedur de rutare ce determin vecinul lui z care se a pe unicul drum de
la z la y , ³i
2. trimite mai departe pachetul c tre acest vecin.
Aceasta va returna eticheta acelui vecin al lui s c ruia îi trebuie trimis mai departe pachetul.
Într-un subtask, scorul submisiei dvs. depinde de eticheta maxim atribuit unei staµii (în
general, cu cât mai mic, cu atât mai bine).
Detalii de implementare
Trebuie s implementaµi urm toarele proceduri:
Fiecare test const în unul sau mai multe scenarii independente (adic diferite descrieri ale
SIB). Pentru ecare test constând în r scenarii, un program ce apeleaz procedurile de mai sus
este rulat de exact dou ori, dup cum urmeaz .
La prima rulare a programului:
procedura label este apelat de r ori,
etichetele returnate sunt reµinute de sistemul de evaluare, ³i
find_next_station nu este apelat .
La a doua rulare a programului:
find_next_station poate apelata de mai multe ori. La ecare apel este ales un
scenariu arbitrar, iar apoi etichetele returnate de procedura label pentru acel scenariu
sunt folosite ca intr ri pentru find_next_station.
label nu este apelata.
Orice informaµie reµinut în variabile statice sau globale la prima rulare nu va disponibila în
procedura find_next_station.
Exemplu
Consider m urm torul apel:
În total sunt 5 staµii ³i 4 leg turi conectând perechile de staµii cu indicii (0,1), (1,2), (1,3) ³i
(2,4).
Etichetele pot orice num r întreg între 0 ³i k 10.
Pentru a raporta urm toarea etichetare:
Indice Eticheta
0 6
1 2
2 9
3 3
4 7
procedura label trebuie s returneze 6, 2, 9, 3, 7. Numerele din urm toarea gur arat indicii
(în stânga) ³i etichetele atribuite (în dreapta).
Acesta înseamn ca staµia ce deµine pachetul are eticheta 9, iar staµia destinaµie a pachetului
are eticheta 6. Etichetele staµiilor de pe drumul pân la staµia destinaµie sunt 9, 2, 6. Prin
urmare, apelul trebuie s returneze 2, reprezentând eticheta staµiei c tre care pachetul trebuie
trimis mai departe (aceasta având indice 1).
S consider m înc un posibil apel:
Procedura trebuie s returneze 3, deoarece staµia destinaµie, având eticheta 3, este vecin al
staµiei cu eticheta 2, ³i prin urmare poate primi pachetul direct.
CAPITOLUL 1. IOI 2020 116
Restricµii
1&r & 10
Pentru ecare apel al procedurii label:
2 & n & 1000
k 'n1
0 & ui, v i & n 1 (oricare ar 0 & i & n 2)
Subtaskuri
1. (5 puncte) k 1000, nicio staµie nu va avea mai mult de 2 vecini.
¬
2. (8 puncte) k 1000, legatura i conecteaz staµiile i 1 ³i f raci2&.
3. (16 puncte) k 1 000 000, cel mult o staµie va avea mai mult de 2 vecini.
(10 puncte) n & 8, k 10
9
4.
9
5. (61 de puncte) k 10
În subtaskul 5 puteµi obµine punctaj parµial. Fie m eticheta maxim returnat de procedura
label, luând în calcul toate scenariile. Scorul dvs. pentru acest subtask este calculat conform
cu urm torul tabel:
Etichet Maxim Scor
m ' 10
9
0
2000 & m $ 10
9
9
50 log5 105 10
m
1000 $ m % 2000 50
m & 1000 61
Sample grader
Sample graderul cite³te intrarea în urm torul format:
linia 1: r
r blocuri urmeaz , ecare descriind câte un singur scenariu. Formatul ec rui bloc este dup
cum urmeaz :
linia 1: n k
linia 2 i (0 & i & n 2): ui v i
linia 1 n: q : num rul de apeluri ale procedurii find_next_station.
linia 2 n j (0 & j & q 1): z j y j wj : indicii staµiilor implicate în al j -lea apel al
procedurii find_next_station. Staµia z j deµine pachetul, staµia y j este destinaµia
pachetului, iar staµia wj este accea c tre care pachetul trebuie trimis mai departe.
r blocuri ce corespund la scenarii consecutive din input. Formatul ec rui bloc este dup cum
urmeaz :
linia 1 j (0 & j & q 1): indicele staµiei a c rei etichet a fost returnat de c tre al j -lea
apel al find_next_station în acest scenariu.
B gaµi de seam cum ecare rulare a sample graderului apeleaz atat label cât ³i
find_next_station.
Suppose we root the tree at the station with the smallest label. We observe that if Brenda
can, given 2 nodes A and B , determine whether
node A is an ancestor of node B
node B is an ancestor of node A
nodes A and B are not ancestors of each other
then Brenda can solve each query as follows:
1. For the source node S , check each neighbouring node to see if it is an ancestor of node S .
` If it is, it must be the parent of node S , which we shall call node P . There can be at
most 1 such node.
` Otherwise, it is a child of node S . Check if it is an ancestor of the destination node T .
If yes, return this child.
2. If no answer is returned by the steps above, either node T is an ancestor of node S or they
are not ancestors of each other. In either case, the answer is node P .
Hence, if Ali can label the stations such that Brenda can check the above just from the labels
of the station, then Brenda can solve all the queries.
Subtask 1
The network is a line. Ali can nd a leaf station and label the stations 0 to N 1 in DFS order in
O N time. Then, node A is an ancestor of node B if and only if A & B , which can be checked
in O 1 time.
Subtask 2
The network is a binary tree. For each station X in the input, Ali can give the label X 1. That
way, the parent of node L is node L©2$. Hence, node A is an ancestor of node B if and only
if A & B and repeatedly applying B L©2$ reaches A before reaching 0. This takes O log N
time per check.
Subtask 3
Ali can give label 0 to the station with degree more than 2, or to any station if no such station
exists, and label its neighbours 1 to M where M is the degree of node 0. If we remove node 0,
the remaining stations will form disjoint lines where one station in each line is adjacent to node
0. For each line, let the station adjacent to node 0 be node L. Ali can label each station X in the
line with d L, X 1000 L where d L, X is the number of edges in the unique path between
station X and node L. After this, node A is an ancestor of node B if and only if A & B and either
A 0 or A%1000 B%1000 which takes O 1 time to check.
Subtask 4
The network is small with at most 8 stations. Select a random station and label it 1, this will be
the root of the tree. For each node L with M children, label it's children L 8 to L 8 M 1.
That way, the parent of node L is node L©8$. Hence, node A is an ancestor of node B if and
only if A & B and repeatedly applying B B ©8$ reaches A before reaching 0. The maximum
possible label is 8 $ 10 .
7 9
Subtask 5
In the general case, select a random station to root the tree and perform a DFS from the root:
counter = 0
dfs(station v):
in[v] = counter++
call dfs(c) for each child c of v
out[v] = counter++
CAPITOLUL 1. IOI 2020 118
call dfs(root)
Suppose Brenda knows inv and outv for the source, destination and the neighbours of the
source.
For any 2 stations v1 and v2 , she can deduce that v1 is an ancestor of v2 if and only if
inv1 $ inv2 $ outv1 , and thus be able to solve the query using the method described in the
previous section.
One simple way to encode this is that Ali can label each station with L inv 1000 outv ,
so Brenda can get inv L©1000 and outv L%1000.
The maximum label will be 999 1000 999 999999 which will get around 65 points if the
rst 4 subtasks are handled separately.
To increase the points further, we can make a few observations (*)
Brenda can nd the parent of the source station s by looking for the neighbouring station v
with the smallest inv or outv , unless ins 0 in which case station s is the root.
If we sort the m children c of station s in ascending order of inv to get c1 , c2 , ..., cm ,
then outc1 inc2 1, outc2 inc3 1 and so on. Also, ins inc1 1 and
outcm outs 1.
Hence, some minor optimisations can be made to get 70-80 points by not encoding some values
of outv and deriving them from the inv of the other neighbours instead.
In order to get 89 points, we need Ali to use a maximum label of 2 000 or 2n. We label each
station v as follows:
If the number of edges in the unique path from station v to the root is even, label the station
with inv .
Otherwise, label the station with outv
To get the full 100 points, we make a nal observation that the exact values of the labels are
not essential since the 89 point solution only needs to know how each label compares with each
other. Since the labels are distinct, we can simply label the stations 0 to N 1 based on the rank
of the labels in the 89 point solution.
16 };
17
18 cout<<"argc = "<<argc<<"\n";
19 for(int kk=0;kk<argc;kk++)
20 cout<<argv[kk]<<"\n";
21 cout<<"----------------------\n";
22
23 registerChecker("stations", argc, argv);
24
25 compareRemainingLines();
26 }
27 /*
28 argc = 4
29 checker
30 ../tests/1-08.in
31 ../tests/1-08.out
32 stations.out
33 ----------------------
34 1
35 Correct
36
37 Process returned 0 (0x0) execution time : 0.031 s
38 Press any key to continue.
39 */
49 if (y == p) continue;
50 dfs(y, s, s + sz[y] - 1, x, h + 1);
51 s += sz[y];
52 }
53
54 assert(s == e + 1);
55 }
56
57 vector<int> label(int n, int k, vector<int> u, vector<int> v)
58 {
59 assert((int)u.size() == n - 1 && (int)v.size() == n - 1);
60 sz = vector<int>(n);
61 labels = vector<int>(n);
62 E = vector<vector<int>>(n);
63 for (int i = 0; i < n - 1; ++i)
64 {
65 E[u[i]].push_back(v[i]);
66 E[v[i]].push_back(u[i]);
67 }
68
69 dfsSiz(0);
70 dfs(0, 0, n - 1);
71
72 return labels;
73 }
74
75 int find_next_station(int s, int t, vector<int> c)
76 {
77 vector<int> sub{s, s};
78 int m = c.size();
79 if (c[0] < s)
80 {
81 if (m > 1) sub[0] = c[1];
82 if (t < sub[0] || t > sub[1]) return c[0];
83 for (int i = 1; i + 1 < m; ++i)
84 if (c[i + 1] > t) return c[i];
85 return c[m - 1];
86 }
87 else
88 {
89 if (s != 0 && m > 1)
90 sub[1] = c[m - 2];
91 else
92 if (s == 0)
93 sub[1] = c[m - 1];
94
95 if (t < sub[0] || t > sub[1])
96 return c[m - 1];
97
98 for (int i = 0;; ++i)
99 if (c[i] >= t) return c[i];
100 }
101 }
102
103 // -----------------------------------------------
104
105 int main()
106 {
107 std::clock_t c_start = std::clock();
108 auto t_start = std::chrono::high_resolution_clock::now();
109
110 auto t1 = clock();
111
112 //std::freopen("../tests/5-49.in", "r", stdin);
113 std::freopen("../tests/1-08.in", "r", stdin);
114 //std::freopen("../tests/0-00.in", "r", stdin);
115
116 std::freopen("stations.out", "w", stdout);
117
118 assert(scanf("%d", &r) == 1);
119
120 auto t2 = clock();
121
122 for (int tc = 0; tc < r; tc++)
123 {
124 assert(scanf("%d%d", &n, &k) == 2);
CAPITOLUL 1. IOI 2020 121
201
202 std::clock_t c_end = std::clock();
203 auto t_end = std::chrono::high_resolution_clock::now();
204
205 // reset console output
206 freopen("CON", "w", stdout);
207
208 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
209 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
210 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
211
212 std::cout << std::fixed << std::setprecision(2)
213 << "\nCPU time used: "
214 << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"
215 << "Wall clock time passed: "
216 << std::chrono::duration<double, std::milli>(t_end-t_start).count()
217 << " ms\n";
218
219 //return 0;
220
221 exit(0);
222 }
127 }
128 }
129
130 assert(scanf("%d", &q) == 1);
131
132 for (int i = 0; i < q; i++)
133 {
134 assert(scanf("%d%d%d", &s, &t, &w) == 3);
135 c.clear();
136 for (int v : adjlist[s])
137 {
138 c.push_back(labels[v]);
139 }
140
141 std::sort(c.begin(), c.end());
142
143 int answer = find_next_station(labels[s], labels[t], c);
144 if (!std::binary_search(c.begin(), c.end(), answer))
145 {
146 printf("Label %d returned by find_next_station \
147 not found in c\n", answer);
148 exit(0);
149 }
150
151 answers.push_back(reverse_labels[answer]);
152 }
153 }
154
155 auto t3 = clock();
156
157 printf("%d\n", max_label);
158 for (int index : answers)
159 {
160 printf("%d\n", index);
161 }
162
163 auto t4 = clock();
164
165 std::clock_t c_end = std::clock();
166 auto t_end = std::chrono::high_resolution_clock::now();
167
168 // reset console output
169 freopen("CON", "w", stdout);
170
171 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
172 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
173 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
174
175 std::cout << std::fixed << std::setprecision(2)
176 << "\nCPU time used: "
177 << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"
178 << "Wall clock time passed: "
179 << std::chrono::duration<double, std::milli>(t_end-t_start).count()
180 << " ms\n";
181
182 //return 0;
183
184 exit(0);
185 }
166 {
167 printf("%d\n", index);
168 }
169
170 auto t4 = clock();
171
172 std::clock_t c_end = std::clock();
173 auto t_end = std::chrono::high_resolution_clock::now();
174
175 // reset console output
176 freopen("CON", "w", stdout);
177
178 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
179 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
180 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
181
182 std::cout << std::fixed << std::setprecision(2)
183 << "\nCPU time used: "
184 << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"
185 << "Wall clock time passed: "
186 << std::chrono::duration<double, std::milli>(t_end-t_start).count()
187 << " ms\n";
188
189 //return 0;
190
191 exit(0);
192 }
46 gri[v[i]].push_back(u[i]);
47 }
48
49 dfs(0,0,0);
50
51 return ret;
52 }
53
54 int find_next_station(int s, int t, vector<int> c)
55 {
56 int m = c.size();
57 if(m == 1) return c[0];
58 for(auto i : c)
59 if(i == t) return i;
60 if(s < c[0])
61 {
62 sort(c.begin(),c.end());
63 if(t < s)return c.back();
64 for(int i = 0; i < m-1; ++i)
65 {
66 if(c[i] > t)return c[i];
67 }
68
69 return c.back();
70 }
71
72 sort(c.rbegin(),c.rend());
73 if(s < t) return c.back();
74 for(int i = 0; i < m-1; ++i)
75 {
76 if(c[i] < t)return c[i];
77 }
78
79 return c.back();
80 }
81
82 // -----------------------------------------------
83
84 int main()
85 {
86 std::clock_t c_start = std::clock();
87 auto t_start = std::chrono::high_resolution_clock::now();
88
89 auto t1 = clock();
90
91 //std::freopen("../tests/5-49.in", "r", stdin);
92 std::freopen("../tests/1-08.in", "r", stdin);
93 //std::freopen("../tests/0-00.in", "r", stdin);
94
95 std::freopen("stations.out", "w", stdout);
96
97 assert(scanf("%d", &r) == 1);
98
99 auto t2 = clock();
100
101 for (int tc = 0; tc < r; tc++)
102 {
103 assert(scanf("%d%d", &n, &k) == 2);
104 u.resize(n - 1);
105 v.resize(n - 1);
106 adjlist.clear();
107 adjlist.resize(n);
108 for (int i = 0; i < n - 1; i++)
109 {
110 assert(scanf("%d%d", &u[i], &v[i]) == 2);
111 adjlist[u[i]].push_back(v[i]);
112 adjlist[v[i]].push_back(u[i]);
113 }
114
115 labels = label(n, k, u, v);
116 if ((int)labels.size() != n) {
117 printf("Number of labels not equal to %d\n", n);
118 exit(0);
119 }
120
121 reverse_labels.clear();
CAPITOLUL 1. IOI 2020 129
122
123 for (int i = 0; i < n; i++)
124 {
125 if (labels[i] < 0 || labels[i] > k)
126 {
127 printf("Label not in range 0 to %d\n", k);
128 exit(0);
129 }
130
131 if (reverse_labels.find(labels[i]) != reverse_labels.end())
132 {
133 printf("Labels not unique\n");
134 exit(0);
135 }
136
137 reverse_labels[labels[i]] = i;
138 if (labels[i] > max_label)
139 {
140 max_label = labels[i];
141 }
142 }
143
144 assert(scanf("%d", &q) == 1);
145
146 for (int i = 0; i < q; i++)
147 {
148 assert(scanf("%d%d%d", &s, &t, &w) == 3);
149 c.clear();
150 for (int v : adjlist[s])
151 {
152 c.push_back(labels[v]);
153 }
154
155 std::sort(c.begin(), c.end());
156
157 int answer = find_next_station(labels[s], labels[t], c);
158 if (!std::binary_search(c.begin(), c.end(), answer))
159 {
160 printf("Label %d returned by find_next_station \
161 not found in c\n", answer);
162 exit(0);
163 }
164
165 answers.push_back(reverse_labels[answer]);
166 }
167 }
168
169 auto t3 = clock();
170
171 printf("%d\n", max_label);
172 for (int index : answers)
173 {
174 printf("%d\n", index);
175 }
176
177 auto t4 = clock();
178
179 std::clock_t c_end = std::clock();
180 auto t_end = std::chrono::high_resolution_clock::now();
181
182 // reset console output
183 freopen("CON", "w", stdout);
184
185 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
186 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
187 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
188
189 std::cout << std::fixed << std::setprecision(2)
190 << "\nCPU time used: "
191 << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"
192 << "Wall clock time passed: "
193 << std::chrono::duration<double, std::milli>(t_end-t_start).count()
194 << " ms\n";
195
196 //return 0;
197
CAPITOLUL 1. IOI 2020 130
198 exit(0);
199 }
71 {
72 return c.back();
73 }
74 else
75 {
76 return *lower_bound(c.begin(), c.end(), t);
77 }
78 }
79 else if (s > c.back())
80 { // postorder
81 if (s < t || t < c[1])
82 {
83 return c[0];
84 }
85 else
86 {
87 int idx = upper_bound(c.begin(), c.end(), t) - c.begin();
88 assert(idx > 0);
89 return c[idx - 1];
90 }
91 }
92 else assert(false);
93
94 return -123;
95 }
96
97 // -----------------------------------------------
98
99 int main()
100 {
101 std::clock_t c_start = std::clock();
102 auto t_start = std::chrono::high_resolution_clock::now();
103
104 auto t1 = clock();
105
106 //std::freopen("../tests/5-49.in", "r", stdin);
107 std::freopen("../tests/1-08.in", "r", stdin);
108 //std::freopen("../tests/0-00.in", "r", stdin);
109
110 std::freopen("stations.out", "w", stdout);
111
112 assert(scanf("%d", &r) == 1);
113
114 auto t2 = clock();
115
116 for (int tc = 0; tc < r; tc++)
117 {
118 assert(scanf("%d%d", &n, &k) == 2);
119 u.resize(n - 1);
120 v.resize(n - 1);
121 adjlist.clear();
122 adjlist.resize(n);
123 for (int i = 0; i < n - 1; i++)
124 {
125 assert(scanf("%d%d", &u[i], &v[i]) == 2);
126 adjlist[u[i]].push_back(v[i]);
127 adjlist[v[i]].push_back(u[i]);
128 }
129
130 labels = label(n, k, u, v);
131 if ((int)labels.size() != n) {
132 printf("Number of labels not equal to %d\n", n);
133 exit(0);
134 }
135
136 reverse_labels.clear();
137
138 for (int i = 0; i < n; i++)
139 {
140 if (labels[i] < 0 || labels[i] > k)
141 {
142 printf("Label not in range 0 to %d\n", k);
143 exit(0);
144 }
145
146 if (reverse_labels.find(labels[i]) != reverse_labels.end())
CAPITOLUL 1. IOI 2020 132
147 {
148 printf("Labels not unique\n");
149 exit(0);
150 }
151
152 reverse_labels[labels[i]] = i;
153 if (labels[i] > max_label)
154 {
155 max_label = labels[i];
156 }
157 }
158
159 assert(scanf("%d", &q) == 1);
160
161 for (int i = 0; i < q; i++)
162 {
163 assert(scanf("%d%d%d", &s, &t, &w) == 3);
164 c.clear();
165 for (int v : adjlist[s])
166 {
167 c.push_back(labels[v]);
168 }
169
170 std::sort(c.begin(), c.end());
171
172 int answer = find_next_station(labels[s], labels[t], c);
173 if (!std::binary_search(c.begin(), c.end(), answer))
174 {
175 printf("Label %d returned by find_next_station \
176 not found in c\n", answer);
177 exit(0);
178 }
179
180 answers.push_back(reverse_labels[answer]);
181 }
182 }
183
184 auto t3 = clock();
185
186 printf("%d\n", max_label);
187 for (int index : answers)
188 {
189 printf("%d\n", index);
190 }
191
192 auto t4 = clock();
193
194 std::clock_t c_end = std::clock();
195 auto t_end = std::chrono::high_resolution_clock::now();
196
197 // reset console output
198 freopen("CON", "w", stdout);
199
200 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
201 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
202 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
203
204 std::cout << std::fixed << std::setprecision(2)
205 << "\nCPU time used: "
206 << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"
207 << "Wall clock time passed: "
208 << std::chrono::duration<double, std::milli>(t_end-t_start).count()
209 << " ms\n";
210
211 //return 0;
212
213 exit(0);
214 }
5 #include <bits/stdc++.h>
6
7 using namespace std;
8
9 static int max_label = 0;
10 static int r, n, k, q;
11
12 static std::vector<int> u, v, answers;
13 static std::vector<int> labels;
14
15 static std::map<int, int> reverse_labels;
16 static std::vector<std::vector<int>> adjlist;
17 static int s, t, w;
18 static std::vector<int> c;
19
20 // -----------------------------------------------
21
22 int ti;
23 vector<int> adj[1005];
24
25 void dfs(int u, int p, int d, vector<int> &labels)
26 {
27 if (d % 2 == 0)
28 labels[u] = ti++;
29 for (int v : adj[u])
30 if (v != p)
31 dfs(v, u, d + 1, labels);
32 if (d % 2 == 1)
33 labels[u] = ti++;
34 }
35
36 std::vector<int> label(int n, int k, std::vector<int> u, std::vector<int> v)
37 {
38 std::vector<int> labels(n);
39
40 ti = 0;
41 for (int i=0; i<n; i++)
42 adj[i].clear();
43
44 for (int i=0; i<n-1; i++)
45 {
46 adj[u[i]].push_back(v[i]);
47 adj[v[i]].push_back(u[i]);
48 }
49
50 dfs(0, -1, 0, labels);
51
52 return labels;
53 }
54
55 int find_next_station(int s, int t, std::vector<int> c)
56 {
57 if (c.back() < s)
58 {
59 // odd depth
60 if (t > s || t < c[0])
61 return c[0];
62
63 for (int i=0; i<(int)c.size()-1; i++)
64 if (t >= c[i] && t < c[i+1])
65 return c[i];
66
67 return c.back();
68 }
69 else
70 {
71 // even depth
72 if (t < s || t > c.back())
73 return c.back();
74
75 for (int i=(int)c.size()-1; i>0; i--)
76 if (t <= c[i] && t > c[i-1])
77 return c[i];
78
79 return c[0];
80 }
CAPITOLUL 1. IOI 2020 134
81 }
82
83 // -----------------------------------------------
84
85 int main()
86 {
87 std::clock_t c_start = std::clock();
88 auto t_start = std::chrono::high_resolution_clock::now();
89
90 auto t1 = clock();
91
92 //std::freopen("../tests/5-49.in", "r", stdin);
93 std::freopen("../tests/1-08.in", "r", stdin);
94 //std::freopen("../tests/0-00.in", "r", stdin);
95
96 std::freopen("stations.out", "w", stdout);
97
98 assert(scanf("%d", &r) == 1);
99
100 auto t2 = clock();
101
102 for (int tc = 0; tc < r; tc++)
103 {
104 assert(scanf("%d%d", &n, &k) == 2);
105 u.resize(n - 1);
106 v.resize(n - 1);
107 adjlist.clear();
108 adjlist.resize(n);
109 for (int i = 0; i < n - 1; i++)
110 {
111 assert(scanf("%d%d", &u[i], &v[i]) == 2);
112 adjlist[u[i]].push_back(v[i]);
113 adjlist[v[i]].push_back(u[i]);
114 }
115
116 labels = label(n, k, u, v);
117 if ((int)labels.size() != n) {
118 printf("Number of labels not equal to %d\n", n);
119 exit(0);
120 }
121
122 reverse_labels.clear();
123
124 for (int i = 0; i < n; i++)
125 {
126 if (labels[i] < 0 || labels[i] > k)
127 {
128 printf("Label not in range 0 to %d\n", k);
129 exit(0);
130 }
131
132 if (reverse_labels.find(labels[i]) != reverse_labels.end())
133 {
134 printf("Labels not unique\n");
135 exit(0);
136 }
137
138 reverse_labels[labels[i]] = i;
139 if (labels[i] > max_label)
140 {
141 max_label = labels[i];
142 }
143 }
144
145 assert(scanf("%d", &q) == 1);
146
147 for (int i = 0; i < q; i++)
148 {
149 assert(scanf("%d%d%d", &s, &t, &w) == 3);
150 c.clear();
151 for (int v : adjlist[s])
152 {
153 c.push_back(labels[v]);
154 }
155
156 std::sort(c.begin(), c.end());
CAPITOLUL 1. IOI 2020 135
157
158 int answer = find_next_station(labels[s], labels[t], c);
159 if (!std::binary_search(c.begin(), c.end(), answer))
160 {
161 printf("Label %d returned by find_next_station \
162 not found in c\n", answer);
163 exit(0);
164 }
165
166 answers.push_back(reverse_labels[answer]);
167 }
168 }
169
170 auto t3 = clock();
171
172 printf("%d\n", max_label);
173 for (int index : answers)
174 {
175 printf("%d\n", index);
176 }
177
178 auto t4 = clock();
179
180 std::clock_t c_end = std::clock();
181 auto t_end = std::chrono::high_resolution_clock::now();
182
183 // reset console output
184 freopen("CON", "w", stdout);
185
186 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
187 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
188 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
189
190 std::cout << std::fixed << std::setprecision(2)
191 << "\nCPU time used: "
192 << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"
193 << "Wall clock time passed: "
194 << std::chrono::duration<double, std::milli>(t_end-t_start).count()
195 << " ms\n";
196
197 //return 0;
198
199 exit(0);
200 }
29 {
30
31 viz[nod] = 1;
32 poz[nod].first = ++idx;
33 for (auto vecin : L[nod])
34 if (!viz[vecin])
35 {
36 fth[vecin] = nod;
37 level[vecin] = 1 + level[nod];
38 dfs (vecin);
39 }
40
41 poz[nod].second = ++idx;
42 }
43
44 int cautare_binara (int n, int val)
45 {
46 int st = 0, dr = n-1;
47 while (st <= dr)
48 {
49 int mid = (st + dr)>>1;
50 if (aux[mid] == val)
51 return mid;
52
53 if (aux[mid] < val)
54 st = mid+1;
55 else
56 dr = mid-1;
57 }
58
59 return -123;
60 }
61
62 vector <int> label (int n, int k, vector <int> u, vector <int> v)
63 {
64 int i;
65
66 for (i=0;i<n;i++)
67 L[i].clear();
68
69 for (i=0;i<n-1;i++)
70 {
71 int x = u[i], y = v[i];
72 L[x].push_back(y);
73 L[y].push_back(x);
74 }
75
76 memset (viz,0,sizeof viz);
77 memset (level,0,sizeof level);
78 memset (poz,0,sizeof poz); // ... ???
79 memset (fth,0,sizeof fth);
80
81 idx = -1;
82
83 dfs (0);
84
85 vector <int> labels;
86 for (i=0;i<n;i++)
87 {
88 if (level[i] % 2 == 0)
89 labels.push_back(poz[i].first);
90 else
91 labels.push_back(poz[i].second);
92 }
93
94 /// pot sa le normalizez??
95 aux = labels;
96 sort (aux.begin(),aux.end());
97 for (i=0;i<n;i++)
98 labels[i] = cautare_binara (n,labels[i]);
99
100 return labels;
101 }
102
103 int find_next_station (int x, int y, vector <int> v)
104 {
CAPITOLUL 1. IOI 2020 137
105 /// mai intai vad daca se afla pe un nivel par sau impar
106
107 int ok = 0;
108 for (auto it : v)
109 if (it < x)
110 {
111 ok = 1;
112 break;
113 }
114
115 if (!ok)
116 { /// labelul x inseamna de fapt un inceput de interval
117
118 if (y < x)
119 return v.back();
120
121 for (auto it : v)
122 if (y <= it)
123 return it;
124
125 return v.back();
126 }
127 else
128 {
129 if (y > x)
130 return v.front();
131
132 for (int i=v.size()-1;i>=0;i--)
133 if (y >= v[i])
134 return v[i];
135
136 return v.front();
137 }
138 }
139
140 // -----------------------------------------------
141
142 int main()
143 {
144 std::clock_t c_start = std::clock();
145 auto t_start = std::chrono::high_resolution_clock::now();
146
147 auto t1 = clock();
148
149 //std::freopen("../tests/5-49.in", "r", stdin);
150 std::freopen("../tests/1-08.in", "r", stdin);
151 //std::freopen("../tests/0-00.in", "r", stdin);
152
153 std::freopen("stations.out", "w", stdout);
154
155 assert(scanf("%d", &r) == 1);
156
157 auto t2 = clock();
158
159 for (int tc = 0; tc < r; tc++)
160 {
161 assert(scanf("%d%d", &n, &k) == 2);
162 u.resize(n - 1);
163 v.resize(n - 1);
164 adjlist.clear();
165 adjlist.resize(n);
166 for (int i = 0; i < n - 1; i++)
167 {
168 assert(scanf("%d%d", &u[i], &v[i]) == 2);
169 adjlist[u[i]].push_back(v[i]);
170 adjlist[v[i]].push_back(u[i]);
171 }
172
173 labels = label(n, k, u, v);
174 if ((int)labels.size() != n) {
175 printf("Number of labels not equal to %d\n", n);
176 exit(0);
177 }
178
179 reverse_labels.clear();
180
CAPITOLUL 1. IOI 2020 138
257 }
72 {
73 for(auto &x : c)
74 {
75 if(x>=t)return x;
76 }
77 }
78
79 return c[sz-1];
80 }
81 else
82 {
83 if(sz>=2)b = c[1];
84 if(b<=t && t<=e)
85 {
86 reverse(c.begin(),c.end());
87 for(auto &x : c)
88 {
89 if(x<=t)return x;
90 }
91 }
92
93 return c[0];
94 }
95 }
96
97 // -----------------------------------------------
98
99 int main()
100 {
101 std::clock_t c_start = std::clock();
102 auto t_start = std::chrono::high_resolution_clock::now();
103
104 auto t1 = clock();
105
106 //std::freopen("../tests/5-49.in", "r", stdin);
107 std::freopen("../tests/1-08.in", "r", stdin);
108 //std::freopen("../tests/0-00.in", "r", stdin);
109
110 std::freopen("stations.out", "w", stdout);
111
112 assert(scanf("%d", &r) == 1);
113
114 auto t2 = clock();
115
116 for (int tc = 0; tc < r; tc++)
117 {
118 assert(scanf("%d%d", &n, &k) == 2);
119 u.resize(n - 1);
120 v.resize(n - 1);
121 adjlist.clear();
122 adjlist.resize(n);
123 for (int i = 0; i < n - 1; i++)
124 {
125 assert(scanf("%d%d", &u[i], &v[i]) == 2);
126 adjlist[u[i]].push_back(v[i]);
127 adjlist[v[i]].push_back(u[i]);
128 }
129
130 labels = label(n, k, u, v);
131 if ((int)labels.size() != n) {
132 printf("Number of labels not equal to %d\n", n);
133 exit(0);
134 }
135
136 reverse_labels.clear();
137
138 for (int i = 0; i < n; i++)
139 {
140 if (labels[i] < 0 || labels[i] > k)
141 {
142 printf("Label not in range 0 to %d\n", k);
143 exit(0);
144 }
145
146 if (reverse_labels.find(labels[i]) != reverse_labels.end())
147 {
CAPITOLUL 1. IOI 2020 141
IOI 201923
Adnan este proprietarul celui mai mare magazin de înc lµ minte din Baku. O cutie ce conµine
n perechi de panto tocmai a sosit în magazin. Fiecare pereche este format din doi panto de
aceea³i m rime: stânga respectiv dreapta. Adnan a pus toµi cei 2n panto î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 pantoi î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 Pantoi 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 panto adiacenµi în acel moment ³i îi interschimb (îi ridic ³i pune
ecare pantof pe locul celuilalt). Doi panto 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 panto.
Detalii de implementare
Exemple
Exemplul 1
S consider m urm torul apel:
count_swaps([2, 1, -1, -2])
23
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).
142
CAPITOLUL 2. IOI 2019 143
Restricµii
Subtaskuri
1. (10 puncte) n 1
2. (20 de puncte) n & 8
3. (20 de puncte) Toµi pantoi sunt de aceea³i m rime.
4. (15 puncte) Toµi pantoi de pe poziµiile 0, ..., n 1 sunt de stânga, iar toµi pantoi de pe
poziµiile n, ..., 2n 1 sunt de dreapta. De asemenea, pentru ecare i (0 & i & n 1), pantoi 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
the left, rst move it until the shoe occupies position k 1, but then instead of moving it further,
simply start moving the shoe that was at position k .
The process can be repeated until the arrangement of the shoes becomes valid. This can
be modelled naively in quadratic time, which solves most of the subtasks, or more eciently in
O n log n using a Fenwick tree or a segment tree.
24
Dac cineva are nevoie de traducere, cred c a nimerit un pic aiurea pe aici!!!
CAPITOLUL 2. IOI 2019 145
50 {
51 vector<int> index = create_index(n, S);
52 Fenwick f = Fenwick(2 * n);
53 long long ans = 0;
54 for (int i = 0; i < 2 * n; i++)
55 {
56 if (S[i] != 0)
57 {
58 int pos = index[-S[i] + n];
59 ans += pos - i - f.count(i, pos) - (S[i] < 0 ? 1 : 0);
60 S[pos] = 0;
61 f.put(pos);
62 }
63 }
64 return ans;
65 }
66
67 vector<int> change(vector<int> v)
68 {
69 int n = (int)v.size() / 2;
70 vector<int> cnt(n, 0);
71 for(int i = 0; i < 2*n; i++)
72 if(v[i] > 0)
73 cnt[v[i] - 1]++;
74
75 for(int i = 1; i < n; i++)
76 cnt[i] += cnt[i-1];
77
78 vector<int> cntl = cnt, cntr = cnt;
79
80 for(int i = 0; i < 2*n; i++)
81 if(v[i] > 0)
82 v[i] = (--cntr[v[i] - 1]) + 1;
83 else
84 v[i] = -((--cntl[-v[i] - 1]) + 1);
85 return v;
86 }
87
88 long long count_swaps(vector<int> S)
89 {
90 S = change(S);
91 int n = S.size() / 2;
92 return count_adjacent(n, S);
93 }
29 }
30
31 int count(int left, int right)
32 {
33 return count(right) - count(left - 1);
34 }
35
36 void put(int index)
37 {
38 for (; index < int(a.size()); index = index | (index + 1))
39 {
40 a[index]++;
41 }
42 }
43 };
44
45 vector<int> create_index(int n, vector<int> &S)
46 {
47 vector<int> index(2 * n + 1);
48 for (int i = 0; i < 2 * n; i++)
49 {
50 index[S[i] + n] = i;
51 }
52 return index;
53 }
54
55 long long count_adjacent(int n, vector<int> &S)
56 {
57 vector<int> index = create_index(n, S);
58 Fenwick f = Fenwick(2 * n);
59 long long ans = 0;
60 for (int i = 0; i < 2 * n; i++)
61 {
62 if (S[i] != 0)
63 {
64 int pos = index[-S[i] + n];
65 ans += pos - i - f.count(i, pos) - (S[i] < 0 ? 1 : 0);
66 S[pos] = 0;
67 f.put(pos);
68 }
69 }
70 return ans;
71 }
72
73 vector<int> change(vector<int> v)
74 {
75 int n = (int)v.size() / 2;
76 vector<int> cnt(n, 0);
77 for(int i = 0; i < 2*n; i++)
78 if(v[i] > 0)
79 cnt[v[i] - 1]++;
80
81 for(int i = 1; i < n; i++)
82 cnt[i] += cnt[i-1];
83
84 vector<int> cntl = cnt, cntr = cnt;
85
86 for(int i = 0; i < 2*n; i++)
87 if(v[i] > 0)
88 v[i] = (--cntr[v[i] - 1]) + 1;
89 else
90 v[i] = -((--cntl[-v[i] - 1]) + 1);
91 return v;
92 }
93
94
95 long long count_swaps(vector<int> S)
96 {
97 S = change(S);
98 int n = S.size() / 2;
99 return count_adjacent(n, S);
100 }
101
102 int read_int()
103 {
104 int x;
CAPITOLUL 2. IOI 2019 148
25 if(v[i] > 0)
26 v[i] = (--cntr[v[i] - 1]) + 1;
27 else
28 v[i] = -((--cntl[-v[i] - 1]) + 1);
29 return v;
30 }
31
32 long long count_swaps(vector<int> s)
33 {
34 s = change(s);
35 vector<pair<int, bool>> in(SZ(s));
36
37 vector<int> where(SZ(s) / 2, -1);
38
39 for (int i = 0; i != SZ(s); ++i)
40 {
41 in[i].first = abs(s[i]) - 1;
42 in[i].second = (s[i] < 0 ? 0 : 1);
43
44 if (where[in[i].first] == -1)
45 where[in[i].first] = i;
46 }
47
48 vector<int> fenw(SZ(in));
49 for (int i = 0; i != SZ(in); ++i)
50 fenw[i] = 1 + i - (i & (i+1));
51
52 long long ans = 0;
53 vector<char> dead(SZ(in), false);
54
55 for (int pos = SZ(in) - 1; pos >= 0; --pos)
56 if (not dead[pos])
57 {
58 dead[pos] = 1;
59
60 int i = where[in[pos].first];
61 dead[i] = 1;
62
63 int dist = 0;
64 for (int p = pos; p >= 0; p = (p & (p + 1)) - 1)
65 dist += fenw[p];
66
67 for (int p = i; p >= 0; p = (p & (p + 1)) - 1)
68 dist -= fenw[p];
69
70 if (in[pos].second == 1)
71 --dist;
72
73 ans += dist;
74 for (int p = i; p < SZ(fenw); p = p | (p + 1))
75 fenw[p] -= 1;
76 }
77
78 return ans;
79 }
80
81
82 int read_int()
83 {
84 int x;
85 if (scanf("%d", &x) != 1)
86 {
87 fprintf(stderr, "Error while reading input\n");
88 exit(1);
89 }
90 return x;
91 }
92
93 int main()
94 {
95 auto t1 = clock();
96
97 std::freopen("../tests/6-15.in", "r", stdin) ;
98 std::freopen("shoes.out", "w", stdout) ;
99
100 int n;
CAPITOLUL 2. IOI 2019 150
41
42 vector<int> create_index(int n, vector<int> &S)
43 {
44 vector<int> index(2 * n + 1);
45 for (int i = 0; i < 2 * n; i++)
46 {
47 index[S[i] + n] = i;
48 }
49 return index;
50 }
51
52 long long count_adjacent(int n, vector<int> &S)
53 {
54 vector<int> index = create_index(n, S);
55 Fenwick f = Fenwick(2 * n);
56 long long ans = 0;
57 for (int i = 0; i < 2 * n; i++)
58 {
59 if (S[i] != 0)
60 {
61 int pos = index[-S[i] + n];
62 ans += pos - i - f.count(i, pos) - (S[i] < 0 ? 1 : 0);
63 S[pos] = 0;
64 f.put(pos);
65 }
66 }
67 return ans;
68 }
69
70 vector<int> change(vector<int> v)
71 {
72 int n = (int)v.size() / 2;
73 vector<int> cnt(n, 0);
74 for(int i = 0; i < 2*n; i++)
75 if(v[i] > 0)
76 cnt[v[i] - 1]++;
77
78 for(int i = 1; i < n; i++)
79 cnt[i] += cnt[i-1];
80
81 vector<int> cntl = cnt, cntr = cnt;
82
83 for(int i = 0; i < 2*n; i++)
84 if(v[i] > 0)
85 v[i] = (--cntr[v[i] - 1]) + 1;
86 else
87 v[i] = -((--cntl[-v[i] - 1]) + 1);
88 return v;
89 }
90
91 long long count_swaps(vector<int> S)
92 {
93 S = change(S);
94 int n = S.size() / 2;
95 return count_adjacent(n, S);
96 }
97
98 int read_int()
99 {
100 int x;
101 if (scanf("%d", &x) != 1)
102 {
103 fprintf(stderr, "Error while reading input\n");
104 exit(1);
105 }
106 return x;
107 }
108
109 int main()
110 {
111 auto t1 = clock();
112
113 std::freopen("../tests/6-15.in", "r", stdin) ;
114 std::freopen("shoes.out", "w", stdout) ;
115
116 int n;
CAPITOLUL 2. IOI 2019 152
117 }
118
119 int read_int()
120 {
121 int x;
122 if (scanf("%d", &x) != 1)
123 {
124 fprintf(stderr, "Error while reading input\n");
125 exit(1);
126 }
127 return x;
128 }
129
130 int main()
131 {
132 auto t1 = clock();
133
134 std::freopen("../tests/6-15.in", "r", stdin) ;
135 std::freopen("shoes.out", "w", stdout) ;
136
137 int n;
138 //assert(1 == scanf("%d", &n));
139 n = read_int();
140
141 vector<int> S(2 * n);
142 for (int i = 0; i < 2 * n; i++)
143 //assert(1 == scanf("%d", &S[i]));
144 S[i] = read_int();
145
146 fclose(stdin);
147
148 auto t2 = clock();
149
150 long long result = count_swaps(S);
151
152 auto t3 = clock();
153
154
155 printf("%lld\n", result);
156 fclose(stdout);
157
158 auto t4 = clock();
159
160 // reset console output
161 freopen("CON", "w", stdout);
162
163 std::cout <<result<<’\n’<<’\n’;
164 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
165 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
166 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
167
168 return 0;
169 }
20
21 sort(S.begin(), S.end());
22 sort(V.begin(), V.end());
23 for (int i = 0; i < 2 * N; ++i)
24 {
25 if (S[i] != V[i])
26 {
27 return false;
28 }
29 }
30
31 return true;
32 }
33
34 void run(std::vector<int> S)
35 {
36 assert(1 <= SUBTASK && SUBTASK <= 6);
37
38 assert(S.size() % 2 == 0);
39 int N = S.size() / 2;
40 assert(1 <= N && N <= 100000);
41
42 map<int, int> sizeToOccurences;
43 for (int s : S)
44 {
45 sizeToOccurences[abs(s)] += s / abs(s);
46 }
47 for (pair<int, int> occurences : sizeToOccurences)
48 {
49 assert(occurences.second == 0);
50 }
51
52 if (SUBTASK == 1)
53 {
54 assert(N == 1);
55 }
56
57 if (SUBTASK == 2)
58 {
59 assert(N <= 8);
60 }
61
62 if (SUBTASK == 3)
63 {
64 for (int s : S)
65 {
66 assert(abs(s) == abs(S[0]));
67 }
68 }
69
70 if (SUBTASK == 4)
71 {
72 for (int i = 0; i < N; ++i)
73 {
74 assert(abs(S[i]) == S[i + N]);
75 }
76 }
77
78 if (SUBTASK == 5)
79 {
80 assert(N <= 1000);
81 }
82 }
83 } // namespace testcaseCheck
84
85 struct FenwickTree
86 {
87 vector<int> arr;
88
89 FenwickTree(int n)
90 {
91 arr.resize(n + 1, 0);
92 }
93
94 void update(int x,int y)
95 {
CAPITOLUL 2. IOI 2019 156
172 int n;
173 //assert(1 == scanf("%d", &n));
174 n = read_int();
175
176 vector<int> S(2 * n);
177 for (int i = 0; i < 2 * n; i++)
178 //assert(1 == scanf("%d", &S[i]));
179 S[i] = read_int();
180
181 fclose(stdin);
182
183 auto t2 = clock();
184
185 long long result = count_swaps(S);
186
187 auto t3 = clock();
188
189 printf("%lld\n", result);
190 fclose(stdout);
191
192 auto t4 = clock();
193
194 // reset console output
195 freopen("CON", "w", stdout);
196
197 std::cout <<result<<’\n’<<’\n’;
198 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
199 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
200 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
201
202 return 0;
203 }
41
42 vector<int> cntl = cnt, cntr = cnt;
43
44 for(int i = 0; i < 2*n; i++)
45 if(v[i] > 0)
46 v[i] = (--cntr[v[i] - 1]) + 1;
47 else
48 v[i] = -((--cntl[-v[i] - 1]) + 1);
49 return v;
50 }
51
52
53 lng count_swaps(vector<int> S)
54 {
55 S = change(S);
56 memset(fen, 0, sizeof fen);
57 memset(_pos, 0, sizeof _pos);
58
59 lng r = 0;
60 for (int i = 0; i < S.size(); i ++)
61 pos[S[i]] = i;
62
63 for (int i = 0; i < S.size(); i ++)
64 if (S[i])
65 {
66 r += pos[-S[i]] - get(pos[-S[i]]) - (S[i] < 0);
67 add(i); add(pos[-S[i]]); S[pos[-S[i]]] = 0; S[i] = 0;
68 }
69 return r;
70 }
71
72
73 int read_int()
74 {
75 int x;
76 if (scanf("%d", &x) != 1)
77 {
78 fprintf(stderr, "Error while reading input\n");
79 exit(1);
80 }
81 return x;
82 }
83
84 int main()
85 {
86 auto t1 = clock();
87
88 std::freopen("../tests/6-15.in", "r", stdin) ;
89 std::freopen("shoes.out", "w", stdout) ;
90
91 int n;
92 //assert(1 == scanf("%d", &n));
93 n = read_int();
94
95 vector<int> S(2 * n);
96 for (int i = 0; i < 2 * n; i++)
97 //assert(1 == scanf("%d", &S[i]));
98 S[i] = read_int();
99
100 fclose(stdin);
101
102 auto t2 = clock();
103
104 long long result = count_swaps(S);
105
106 auto t3 = clock();
107
108
109 printf("%lld\n", result);
110 fclose(stdout);
111
112 auto t4 = clock();
113
114 // reset console output
115 freopen("CON", "w", stdout);
116
CAPITOLUL 2. IOI 2019 159
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 2. IOI 2019 160
O posibil soluµie corect este 1, 1, 1, 1, 2, 2, 3, 3, 3. Aceast soluµie descrie urm toarea îm-
p 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
5
6 vector <int> find_split(int n, int a, int b, int c, vector <int> p,
7 vector <int> q)
8 {
9 vector <pair <int, int> > edges;
10
11 for(int i=0; i<(int)p.size(); i++) edges.emplace_back(p[i], q[i]);
12
13 vector <pair <int, int> > sizes = {{a,0}, {b,1}, {c,2}};
14
15 sort(sizes.begin(), sizes.end());
16 a = sizes[0].first; b = sizes[1].first; c = sizes[2].first;
17
18 vector <int> rep(n), siz(n);
19
20 for(int i=0; i<n; i++)
21 {
22 rep[i] = i;
23 siz[i] = 1;
24 }
25
26 function <int(int)> find = [&](int x)
27 {
28 if(rep[x] == x) return x;
29 return rep[x] = find(rep[x]);
30 };
31
32 auto unia = [&](int aa, int bb) -> bool
33 {
34 int fa = find(aa), fb = find(bb);
35 if(fa == fb) return false;
36 if(siz[fa] < siz[fb]) swap(fa, fb);
37 siz[fa] += siz[fb];
38 rep[fb] = fa;
39 return true;
40 };
41
42 vector <vector <int> > G(n);
43 vector <pair <int, int> > non_tree;
44
45 for(auto edge : edges)
46 {
47 if(unia(edge.first, edge.second))
48 {
49 G[edge.first].push_back(edge.second);
50 G[edge.second].push_back(edge.first);
51 }
52 else
53 {
54 non_tree.push_back(edge);
55 }
56 }
57
58 vector <bool> vis(n);
59 vector <int> subtree(n);
60
61 function<void(int)> dfs1 = [&](int v)
62 {
63 vis[v] = true;
64 subtree[v] = 1;
65 for(auto w : G[v]) if(!vis[w])
66 {
67 dfs1(w);
68 subtree[v] += subtree[w];
69 }
70 };
71
72 dfs1(0);
73
74 vis = vector<bool>(n, false);
75 pair <int, int> both_dir = {-1, -1};
76 vector <pair <int, int> > dir;
77
78 function<void(int)> dfs2 = [&](int v)
79 {
80 vis[v] = true;
CAPITOLUL 2. IOI 2019 164
1 #include "bits/stdc++.h"
2 #include "split.h"
3
4 #include <time.h> /* clock */
5 #include <stdio.h>
6
7 using namespace std;
8
9 vector <int> find_split(int n, int a, int b, int c,
10 vector <int> p, vector <int> q)
11 {
12 vector <pair <int, int> > edges;
13
14 for(int i=0; i<(int)p.size(); i++)
15 edges.emplace_back(p[i], q[i]);
16
17 vector <pair <int, int> > sizes = {{a,0}, {b,1}, {c,2}};
18
19 sort(sizes.begin(), sizes.end());
20
21 a = sizes[0].first;
22 b = sizes[1].first;
23 c = sizes[2].first;
24
25 vector <int> rep(n), siz(n);
26
27 for(int i=0; i<n; i++)
28 {
29 rep[i] = i;
30 siz[i] = 1;
31 }
32
33 function <int(int)> find = [&](int x)
34 {
35 if(rep[x] == x) return x;
36 return rep[x] = find(rep[x]);
37 };
38
39 auto unia = [&](int aa, int bb) -> bool
40 {
41 int fa = find(aa), fb = find(bb);
42 if(fa == fb) return false;
43 if(siz[fa] < siz[fb]) swap(fa, fb);
44 siz[fa] += siz[fb];
45 rep[fb] = fa;
46 return true;
47 };
48
49 vector <vector <int> > G(n);
50 vector <pair <int, int> > non_tree;
51
52 for(auto edge : edges)
53 {
54 if(unia(edge.first, edge.second))
55 {
56 G[edge.first].push_back(edge.second);
57 G[edge.second].push_back(edge.first);
58 }
59 else
60 {
61 non_tree.push_back(edge);
62 }
63 }
64
65 vector <bool> vis(n);
66 vector <int> subtree(n);
67
68 function<void(int)> dfs1 = [&](int v)
69 {
70 vis[v] = true;
71 subtree[v] = 1;
72 for(auto w : G[v]) if(!vis[w])
73 {
74 dfs1(w);
75 subtree[v] += subtree[w];
76 }
CAPITOLUL 2. IOI 2019 166
77
78 };
79
80 dfs1(0);
81
82 vis = vector<bool>(n, false);
83 pair <int, int> both_dir = {-1, -1};
84 vector <pair <int, int> > dir;
85
86 function<void(int)> dfs2 = [&](int v)
87 {
88 vis[v] = true;
89 for(auto w : G[v]) if(!vis[w])
90 {
91 int below = subtree[w], above = n - subtree[w];
92 if(min(below, above) >= a)
93 {
94 if(above < below) both_dir = {v, w};
95 else both_dir = {w, v};
96 }
97 else
98 {
99 if(below < a) dir.emplace_back(v, w);
100 else if(above < a) dir.emplace_back(w, v);
101 }
102 dfs2(w);
103 }
104 };
105
106 dfs2(0);
107
108 auto find_solution = [&](int pa, int pb) -> vector<int>
109 {
110 vector <int> ret(n, -1);
111 int counter;
112
113 function<void(int, int)> dfs3 = [&](int v, int mark)
114 {
115 if(counter == 0) return;
116 --counter;
117 ret[v] = mark;
118 for(auto w : G[v]) if(ret[w] == -1) dfs3(w, mark);
119 };
120
121 ret[pa] = sizes[0].second;
122 ret[pb] = sizes[a].second;
123
124 counter = a;
125 dfs3(pa, sizes[0].second);
126 vis[pb] = sizes[1].second;
127
128 counter = b;
129 dfs3(pb, sizes[1].second);
130 vis[pa] = false;
131
132 for(int i=0; i<n; i++)
133 if(ret[i] == -1) ret[i] = sizes[2].second;
134 for(int i=0; i<n; i++)
135 ret[i]++;
136
137 return ret;
138 };
139
140 if(both_dir.first != -1)
141 {
142 return find_solution(both_dir.first, both_dir.second);
143 }
144 else
145 {
146 vector <int> in_deg(n);
147 for(auto edge : dir) in_deg[edge.second]++;
148 vector <int> CH;
149 for(int i=0; i<n; i++) if(in_deg[i] == 0) CH.push_back(i);
150 assert((int)CH.size() == 1);
151 vis = vector<bool>(n, false);
152 subtree = vector<int>(n, 0);
CAPITOLUL 2. IOI 2019 167
229
230 return 0;
231 }
70 }
71
72 int lef,tar;
73 bool vis[mn];
74 int conv[4];
75
76 void dfs3(int x)
77 {
78 if(!lef)return;
79 vis[x]=1;
80 lef--;
81 ans[x]=conv[tar];
82 for(int y:g[x])
83 {
84 if(!vis[y])
85 {
86 dfs3(y);
87 if(!lef)return;
88 }
89 }
90 }
91
92 vector<int> find_split(int N, int a, int b, int c,
93 vector<int> p, vector<int> q)
94 {
95 int sm=min(a,min(b,c)),bi=max(a,max(b,c));
96
97 if(a==sm)
98 conv[1]=1;
99 else
100 if(a==bi)
101 conv[3]=1;
102 else
103 conv[2]=1;
104
105 if(b==sm&&!conv[1]) conv[1]=2;
106 else
107 if(b==bi&&!conv[3])conv[3]=2;
108 else conv[2]=2;
109
110 if(c==sm&&!conv[1])conv[1]=3;
111 else
112 if(c==bi&&!conv[3])conv[3]=3;
113 else conv[2]=3;
114
115 b=a+b+c-sm-bi;
116 a=sm;
117 c=bi;
118 n=N;
119 ans.resize(n,conv[3]);
120 int m=p.size(),i;
121
122 init();
123 for(i=0;i<m;i++)
124 {
125 if(f(p[i])!=f(q[i]))
126 {
127 mrg(p[i],q[i]);
128 g[p[i]].push_back(q[i]);
129 g[q[i]].push_back(p[i]);
130 }
131 }
132
133 dfs(0,-1);
134
135 ctr=fc(0,-1);
136 init();
137 for(int y:g[ctr])
138 {
139 dfs2(y,ctr);
140 if(siz(y)>=a)
141 {
142 vis[ctr]=1;
143 lef=a;
144 tar=1;
145 dfs3(y);
CAPITOLUL 2. IOI 2019 170
146 lef=b;
147 tar=2;
148 vis[ctr]=0;
149 dfs3(ctr);
150 return ans;
151 }
152 }
153
154 for(i=0;i<m;i++)
155 {
156 if(p[i]==ctr||q[i]==ctr)continue;
157 if(f(p[i])==f(q[i]))continue;
158 mrg(p[i],q[i]);
159 g[p[i]].push_back(q[i]);
160 g[q[i]].push_back(p[i]);
161 if(siz(p[i])>=a)
162 {
163 vis[ctr]=1;
164 lef=a;
165 tar=1;
166 dfs3(p[i]);
167 lef=b;
168 tar=2;
169 vis[ctr]=0;
170 dfs3(ctr);
171 return ans;
172 }
173 }
174
175 fill(ans.begin(),ans.end(),0);
176 return ans;
177 }
178
179 int read_int()
180 {
181 int x;
182 if (scanf("%d", &x) != 1)
183 {
184 fprintf(stderr, "Error while reading input\n");
185 exit(1);
186 }
187 return x;
188 }
189
190 int main()
191 {
192 auto t1 = clock();
193
194 //std::freopen("../tests/1-03.in", "r", stdin) ;
195 std::freopen("../tests/5-34.in", "r", stdin) ;
196
197 std::freopen("split.out", "w", stdout) ;
198
199 int n, m, a, b, c;
200 //assert(5 == scanf("%d%d%d%d%d", &n, &m, &a, &b, &c));
201 n = read_int();
202 m = read_int();
203 a = read_int();
204 b = read_int();
205 c = read_int();
206
207 vector<int> p(m), q(m);
208 for (int i=0; i<m; i++)
209 //assert(2 == scanf("%d%d", &p[i], &q[i]));
210 p[i] = read_int(), q[i] = read_int();
211
212 fclose(stdin);
213
214 auto t2 = clock();
215
216 vector<int> result = find_split(n, a, b, c, p, q);
217
218 auto t3 = clock();
219
220 for (int i=0; i<(int)result.size(); i++)
221 printf("%s%d", ((i>0)?" ":""), result[i]);
CAPITOLUL 2. IOI 2019 171
222 printf("\n");
223 fclose(stdout);
224
225 auto t4 = clock();
226
227 // reset console output
228 freopen("CON", "w", stdout);
229
230 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
231 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
232 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
233
234 return 0;
235 }
59
60 return ans;
61 }
62 }
63
64 struct disj
65 {
66 int pa[MAXN], sz[MAXN];
67 void init(int n)
68 {
69 iota(pa, pa + n + 1, 0);
70 fill(sz, sz + n + 1, 1);
71 }
72
73 int find(int x)
74 {
75 return pa[x] = (pa[x] == x ? x : find(pa[x]));
76 }
77
78 int getsz(int x)
79 {
80 return sz[find(x)];
81 }
82
83 bool uni(int p, int q)
84 {
85 p = find(p); q = find(q);
86 if(p == q) return 0;
87 sz[p] += sz[q];
88 pa[q] = p;
89 return 1;
90 }
91 } disj;
92
93 int sz[MAXN], msz[MAXN];
94
95 void dfsc(int x, int p)
96 {
97 sz[x] = 1; msz[x] = 0;
98 for(auto &i : tr[x])
99 {
100 if(i != p)
101 {
102 dfsc(i, x);
103 sz[x] += sz[i];
104 msz[x] = max(msz[x], sz[i]);
105 }
106 }
107 }
108
109 int get_center()
110 {
111 dfsc(0, 0);
112 pi ret(1e9, 1e9);
113 for(int i=0; i<n; i++)
114 {
115 ret = min(ret, pi(max(msz[i], n - sz[i]), i));
116 }
117 return ret.second;
118 }
119
120 void dfs(int x, int p, vector<int> &dfn)
121 {
122 dfn.push_back(x);
123 for(auto &i : tr[x])
124 {
125 if(i != p)
126 {
127 disj.uni(x, i);
128 dfs(i, x, dfn);
129 }
130 }
131 }
132
133 bool vis[MAXN];
134
CAPITOLUL 2. IOI 2019 173
79 int element = 0;
80 if (n - sizev[v] + removablesSum < b[1].first)
81 element = 1;
82
83 result[v] = b[element].second;
84 mark[v] = 2;
85 int goal = b[element].first - 1;
86 forn(i, a[v].size())
87 {
88 if (mark[a[v][i]] < 2 &&
89 goal > 0 &&
90 mintime[a[v][i]] >= startingtime[v] &&
91 startingtime[a[v][i]] > startingtime[v])
92 goal -= dfs2(a[v][i], goal, b[element].second);
93 }
94
95 forn(i, a[v].size())
96 {
97 if (mark[a[v][i]] < 2 &&
98 goal > 0 &&
99 mintime[a[v][i]] < startingtime[v] &&
100 startingtime[a[v][i]] > startingtime[v])
101 goal -= dfs2(a[v][i], goal, b[element].second);
102 }
103
104 dfs2(0, b[1-element].first, b[1-element].second, true);
105 forn(i, n)
106 if (result[i]==0)
107 result[i]=b[2].second;
108 }
109 }
110
111 vector <int> find_split(int n_, int a_, int b_, int c_,
112 vector <int> p, vector <int> q)
113 {
114 n = n_;
115 b[0]=intpair(a_, 1);
116 b[1]=intpair(b_, 2);
117 b[2]=intpair(c_, 3);
118
119 sort(b, b+3);
120
121 forn(i, p.size())
122 {
123 a[p[i]].push_back(q[i]);
124 a[q[i]].push_back(p[i]);
125 }
126
127 dfs(0, -1);
128
129 result.resize(n);
130 return result;
131 }
132
133 int read_int()
134 {
135 int x;
136 if (scanf("%d", &x) != 1)
137 {
138 fprintf(stderr, "Error while reading input\n");
139 exit(1);
140 }
141 return x;
142 }
143
144 int main()
145 {
146 auto t1 = clock();
147
148 //std::freopen("../tests/1-03.in", "r", stdin) ;
149 std::freopen("../tests/5-34.in", "r", stdin) ;
150
151 std::freopen("split.out", "w", stdout) ;
152
153 int n, m, a, b, c;
154 //assert(5 == scanf("%d%d%d%d%d", &n, &m, &a, &b, &c));
CAPITOLUL 2. IOI 2019 177
155 n = read_int();
156 m = read_int();
157 a = read_int();
158 b = read_int();
159 c = read_int();
160
161 vector<int> p(m), q(m);
162 for (int i=0; i<m; i++)
163 //assert(2 == scanf("%d%d", &p[i], &q[i]));
164 p[i] = read_int(), q[i] = read_int();
165
166 fclose(stdin);
167
168 auto t2 = clock();
169
170 vector<int> result = find_split(n, a, b, c, p, q);
171
172 auto t3 = clock();
173
174 for (int i=0; i<(int)result.size(); i++)
175 printf("%s%d", ((i>0)?" ":""), result[i]);
176 printf("\n");
177 fclose(stdout);
178
179 auto t4 = clock();
180
181 // reset console output
182 freopen("CON", "w", stdout);
183
184 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
185 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
186 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
187
188 return 0;
189 }
38 }
39
40 template<class t> ostream& operator<<(ostream& os,const vc<t>& v)
41 {
42 os<<"{";
43 for(auto e:v)os<<e<<",";
44 return os<<"}";
45 }
46
47 const int nmmax=200010;
48
49 vc<pi> g[nmmax];
50 int ans[nmmax];
51 bool us[nmmax];
52
53 void puti(int v,int i,int&rem)
54 {
55 if(ans[v]||rem==0)return;
56 ans[v]=i;
57 rem--;
58 for(auto e:g[v])if(us[e.b])
59 puti(e.a,i,rem);
60 }
61
62 bool vis[nmmax];
63 //find any spanning tree
64 void dfs1(int v,int pe)
65 {
66 if(vis[v])return;
67 vis[v]=1;
68 if(pe!=-1)
69 us[pe]=1;
70 for(auto e:g[v])
71 dfs1(e.a,e.b);
72 }
73
74 //find a centroid
75 int dfs2(int v,int p,int n)
76 {
77 int s=1,mx=0;
78 for(auto e:g[v])if(us[e.b]&&p!=e.a)
79 {
80 int f=dfs2(e.a,v,n);
81 if(f<=0)return f;
82 chmax(mx,f);
83 s+=f;
84 }
85 chmax(mx,n-s);
86 if(mx*2<=n)return -v;
87 return s;
88 }
89
90 void dfs3(int v,int p,vi&w)
91 {
92 w.pb(v);
93 for(auto e:g[v])if(us[e.b]&&p!=e.a)
94 dfs3(e.a,v,w);
95 }
96
97 vector<int> find_split(int n, int a, int b, int c,
98 vector<int> p, vector<int> q)
99 {
100 vc<pi> si{pi(a,1),pi(b,2),pi(c,3)};
101 sort(all(si));
102
103 int m=p.size();
104 rep(i,m)
105 {
106 g[p[i]].eb(q[i],i);
107 g[q[i]].eb(p[i],i);
108 }
109
110 dfs1(0,-1);
111
112 int r=-dfs2(0,-1,n);
113
CAPITOLUL 2. IOI 2019 179
190 return x;
191 }
192
193 int main()
194 {
195 auto t1 = clock();
196
197 //std::freopen("../tests/1-03.in", "r", stdin) ;
198 std::freopen("../tests/5-34.in", "r", stdin) ;
199
200 std::freopen("split.out", "w", stdout) ;
201
202 int n, m, a, b, c;
203 //assert(5 == scanf("%d%d%d%d%d", &n, &m, &a, &b, &c));
204 n = read_int();
205 m = read_int();
206 a = read_int();
207 b = read_int();
208 c = read_int();
209
210 vector<int> p(m), q(m);
211 for (int i=0; i<m; i++)
212 //assert(2 == scanf("%d%d", &p[i], &q[i]));
213 p[i] = read_int(), q[i] = read_int();
214
215 fclose(stdin);
216
217 auto t2 = clock();
218
219 vector<int> result = find_split(n, a, b, c, p, q);
220
221 auto t3 = clock();
222
223 for (int i=0; i<(int)result.size(); i++)
224 printf("%s%d", ((i>0)?" ":""), result[i]);
225 printf("\n");
226 fclose(stdout);
227
228 auto t4 = clock();
229
230 // reset console output
231 freopen("CON", "w", stdout);
232
233 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
234 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
235 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
236
237 return 0;
238 }
2.3 Rectangles
Problema 3 - Rectangles 100 de puncte
Author: Peyman Jabbarzade
În plus, o zon este considerat valid dac ³i numai dac pentru ecare 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 e 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 e stabilit palatul (num rul de moduri în care se pot alege valorile r1 , r2 , c1 ³i c2 care denesc
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 nding 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
25
structure libraries such as STL maps .
25
time-consuming
CAPITOLUL 2. IOI 2019 183
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 dene a structure for a valid rectangle. At most 2 16 structures exist
and for each structure there is a block corner that uniquely dene the valid rectangle.
2 2
Therefore, the number of valid rectangles is bounded by O n . After nding these O n
2
candidate rectangles, we can check each of them in O 1 after a preprocess in O n .
25
26 inline void close()
27 {
28 ::close(inputFileDescriptor);
29 }
30
31 inline char read()
32 {
33 assert(numChars != -1);
34 if (curChar >= numChars)
35 {
36 curChar = 0;
37 numChars = ::read(inputFileDescriptor, buf, SIZE);
38 if (numChars == -1)
39 return -1;
40 }
41 return buf[curChar++];
42 }
43
44 inline int readInt()
45 {
46 int c = eatWhite();
47 int sgn = 1;
48 if (c == ’-’)
49 {
50 sgn = -1;
51 c = read();
52 }
53 int res = 0;
54 do
55 {
56 assert(c >= ’0’ && c <= ’9’);
57 res *= 10;
58 res += c - ’0’;
59 c = read();
60 }
61 while (!isSpaceChar(c));
62 return res * sgn;
63 }
64
65 inline string readString()
66 {
67 char c = eatWhite();
68 string res;
69 do
70 {
71 res += c;
72 c = read();
73 } while (!isSpaceChar(c));
74 return res;
75 }
76
77 inline string readLine()
78 {
79 string res;
80 while (true)
81 {
82 char c = read();
83 if (c == ’\n’ || c == ’\r’ || c == -1)
84 break;
85 res += c;
86 }
87 return res;
88 }
89
90 inline char eatWhite()
91 {
92 char c = read();
93 while (isSpaceChar(c))
94 c = read();
95 return c;
96 }
97
98 static inline bool isSpaceChar(char c)
99 {
100 return c == ’ ’ || c == ’\n’ || c == ’\r’ || c == ’\t’ || c == -1;
CAPITOLUL 2. IOI 2019 185
101 }
102 };
103
104
105 int main()
106 {
107 InputReader inputReader(STDIN_FILENO);
108 int n, m;
109 n = inputReader.readInt();
110 m = inputReader.readInt();
111 vector<vector<int>> a(n, vector<int>(m));
112 for (int i = 0; i < n; i++)
113 {
114 for (int j = 0; j < m; j++)
115 {
116 a[i][j] = inputReader.readInt();
117 }
118 }
119 inputReader.close();
120
121 long long result = count_rectangles(a);
122
123 printf("%lld\n", result);
124 fclose(stdout);
125 return 0;
126 }
47 rof(j, m, 0)
48 {
49 while(t && H[i][j] > H[i][st[t-1]]) t--;
50 R[i][j] = (t ? st[t-1] : -1);
51 st[t++] = j;
52 }
53 }
54 rep(j, m)
55 {
56 int t = 0;
57 rep(i, n)
58 {
59 while(t && H[i][j] > H[st[t-1]][j]) t--;
60 U[i][j] = (t ? st[t-1] : -1);
61 st[t++] = i;
62 }
63 }
64 rep(j, m)
65 {
66 int t = 0;
67 rof(i, n, 0)
68 {
69 while(t && H[i][j] > H[st[t-1]][j]) t--;
70 D[i][j] = (t ? st[t-1] : -1);
71 st[t++] = i;
72 }
73 }
74
75 rep(j, m) rep(i, n)
76 {
77 if(U[i][j] != -1)
78 {
79 if(j > 0 && U[i][j] == U[i][j-1]) UL[i][j] = UL[i][j-1];
80 else if(j > 0 && i == D[U[i][j]][j-1]) UL[i][j] = DL[U[i][j]][j-1];
81 else UL[i][j] = j;
82 }
83 if(D[i][j] != -1)
84 {
85 if(j > 0 && D[i][j] == D[i][j-1]) DL[i][j] = DL[i][j-1];
86 else if(j > 0 && i == U[D[i][j]][j-1]) DL[i][j] = UL[D[i][j]][j-1];
87 else DL[i][j] = j;
88 }
89 }
90
91 rep(i, n) rep(j, m)
92 {
93 if(L[i][j] != -1)
94 {
95 if(i > 0 && L[i][j] == L[i-1][j]) LU[i][j] = LU[i-1][j];
96 else if(i > 0 && j == R[i-1][L[i][j]]) LU[i][j] = RU[i-1][L[i][j]];
97 else LU[i][j] = i;
98 }
99 if(R[i][j] != -1)
100 {
101 if(i > 0 && R[i][j] == R[i-1][j]) RU[i][j] = RU[i-1][j];
102 else if(i > 0 && j == L[i-1][R[i][j]]) RU[i][j] = LU[i-1][R[i][j]];
103 else RU[i][j] = i;
104 }
105 }
106 }
107
108 void check(int i1, int i2, int j1, int j2)
109 {
110 if(i2 < i1 || j2 < j1) return;
111 if(!((R[i2][j1-1]-1 == j2 && RU[i2][j1-1] <= i1) ||
112 (L[i2][j2+1]+1 == j1 && LU[i2][j2+1] <= i1))) return;
113 if(!((D[i1-1][j2]-1 == i2 && DL[i1-1][j2] <= j1) ||
114 (U[i2+1][j2]+1 == i1 && UL[i2+1][j2] <= j1))) return;
115 v.pb((((ll)i1 * maxn + i2) * maxn + j1) * maxn + j2);
116 }
117
118 int count_rectangles(vector<vector<int>> _H)
119 {
120 H = _H;
121 n = sz(H);
122 m = sz(H[0]);
CAPITOLUL 2. IOI 2019 187
123
124 precalc();
125
126 fer(i, 1, n-1) fer(j, 1, m-1)
127 {
128 if(U[i+1][j] != -1 && L[i][j+1] != -1)
129 check(U[i+1][j]+1, i, L[i][j+1]+1, j);
130 if(U[i+1][j] != -1 && R[i][j-1] != -1)
131 check(U[i+1][j]+1, i, j, R[i][j-1]-1);
132 if(D[i-1][j] != -1 && L[i][j+1] != -1)
133 check(i, D[i-1][j]-1, L[i][j+1]+1, j);
134 if(D[i-1][j] != -1 && R[i][j-1] != -1)
135 check(i, D[i-1][j]-1, j, R[i][j-1]-1);
136 if(D[i-1][j] != -1 && R[D[i-1][j]-1][j-1] != -1)
137 check(i, D[i-1][j]-1, j, R[D[i-1][j]-1][j-1]-1);
138 if(D[i-1][j] != -1 && L[D[i-1][j]-1][j+1] != -1)
139 check(i, D[i-1][j]-1, L[D[i-1][j]-1][j+1]+1, j);
140 }
141
142 sort(all(v));
143 v.resize(unique(all(v)) - v.begin());
144
145 return sz(v);
146 }
49 rep(i, n)
50 {
51 int t = 0;
52 rof(j, m, 0)
53 {
54 while(t && H[i][j] > H[i][st[t-1]]) t--;
55 R[i][j] = (t ? st[t-1] : -1);
56 st[t++] = j;
57 }
58 }
59
60 rep(j, m)
61 {
62 int t = 0;
63 rep(i, n)
64 {
65 while(t && H[i][j] > H[st[t-1]][j]) t--;
66 U[i][j] = (t ? st[t-1] : -1);
67 st[t++] = i;
68 }
69 }
70
71 rep(j, m)
72 {
73 int t = 0;
74 rof(i, n, 0)
75 {
76 while(t && H[i][j] > H[st[t-1]][j]) t--;
77 D[i][j] = (t ? st[t-1] : -1);
78 st[t++] = i;
79 }
80 }
81
82 rep(j, m) rep(i, n)
83 {
84 if(U[i][j] != -1)
85 {
86 if(j > 0 && U[i][j] == U[i][j-1])
87 UL[i][j] = UL[i][j-1];
88 else
89 if(j > 0 && i == D[U[i][j]][j-1])
90 UL[i][j] = DL[U[i][j]][j-1];
91 else
92 UL[i][j] = j;
93 }
94
95 if(D[i][j] != -1)
96 {
97 if(j > 0 && D[i][j] == D[i][j-1])
98 DL[i][j] = DL[i][j-1];
99 else
100 if(j > 0 && i == U[D[i][j]][j-1])
101 DL[i][j] = UL[D[i][j]][j-1];
102 else
103 DL[i][j] = j;
104 }
105 }
106
107 rep(i, n) rep(j, m)
108 {
109 if(L[i][j] != -1)
110 {
111 if(i > 0 && L[i][j] == L[i-1][j])
112 LU[i][j] = LU[i-1][j];
113 else
114 if(i > 0 && j == R[i-1][L[i][j]])
115 LU[i][j] = RU[i-1][L[i][j]];
116 else
117 LU[i][j] = i;
118 }
119
120 if(R[i][j] != -1)
121 {
122 if(i > 0 && R[i][j] == R[i-1][j])
123 RU[i][j] = RU[i-1][j];
124 else
CAPITOLUL 2. IOI 2019 189
201
202 inline void close()
203 {
204 ::close(inputFileDescriptor);
205 }
206
207 inline char read()
208 {
209 assert(numChars != -1);
210 if (curChar >= numChars)
211 {
212 curChar = 0;
213 numChars = ::read(inputFileDescriptor, buf, SIZE);
214
215 if (numChars == -1)
216 return -1;
217 }
218
219 return buf[curChar++];
220 }
221
222 inline int readInt()
223 {
224 int c = eatWhite();
225 int sgn = 1;
226 if (c == ’-’)
227 {
228 sgn = -1;
229 c = read();
230 }
231
232 int res = 0;
233 do
234 {
235 assert(c >= ’0’ && c <= ’9’);
236 res *= 10;
237 res += c - ’0’;
238 c = read();
239 } while (!isSpaceChar(c));
240
241 return res * sgn;
242 }
243
244 inline string readString()
245 {
246 char c = eatWhite();
247 string res;
248 do
249 {
250 res += c;
251 c = read();
252 } while (!isSpaceChar(c));
253
254 return res;
255 }
256
257 inline string readLine()
258 {
259 string res;
260 while (true)
261 {
262 char c = read();
263 if (c == ’\n’ || c == ’\r’ || c == -1)
264 break;
265 res += c;
266 }
267
268 return res;
269 }
270
271 inline char eatWhite()
272 {
273 char c = read();
274 while (isSpaceChar(c))
275 c = read();
276 return c;
CAPITOLUL 2. IOI 2019 191
277 }
278
279 static inline bool isSpaceChar(char c)
280 {
281 return c == ’ ’ || c == ’\n’ || c == ’\r’ || c == ’\t’ || c == -1;
282 }
283 };
284
285
286 int main()
287 {
288 auto t1 = clock();
289
290 //std::freopen("../tests/7-18.in", "r", stdin) ; // execution time : 24.047 s
291 //std::freopen("../tests/7-15.in", "r", stdin) ; // execution time : 13.788 s
292 //std::freopen("../tests/7-01.in", "r", stdin) ; // execution time : 4.881 s
293 std::freopen("../tests/6-07.in", "r", stdin) ; // execution time : 3.562 s s
294
295 std::freopen("rectangle.out", "w", stdout) ;
296
297 InputReader inputReader(STDIN_FILENO);
298
299 int n, m;
300 n = inputReader.readInt();
301 m = inputReader.readInt();
302 cerr<<"cerr : "<<n<<" "<<m<<"\n";
303
304 vector<vector<int>> a(n, vector<int>(m));
305 for (int i = 0; i < n; i++)
306 {
307 for (int j = 0; j < m; j++)
308 {
309 a[i][j] = inputReader.readInt();
310 }
311 }
312
313 inputReader.close();
314
315 auto t2 = clock();
316
317 long long result = count_rectangles(a);
318
319 auto t3 = clock();
320
321 printf("%lld\n", result);
322 fclose(stdout);
323
324 auto t4 = clock();
325
326 // reset console output
327 freopen("CON", "w", stdout);
328
329 std::cout <<"result = "<<result<<’\n’<<’\n’;
330
331 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
332 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
333 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
334
335 return 0;
336 }
337 // --------------- end grader ---------------------
164 c = read();
165 }
166
167 int res = 0;
168 do
169 {
170 assert(c >= ’0’ && c <= ’9’);
171 res *= 10;
172 res += c - ’0’;
173 c = read();
174 } while (!isSpaceChar(c));
175
176 return res * sgn;
177 }
178
179 inline string readString()
180 {
181 char c = eatWhite();
182 string res;
183 do
184 {
185 res += c;
186 c = read();
187 } while (!isSpaceChar(c));
188
189 return res;
190 }
191
192 inline string readLine()
193 {
194 string res;
195 while (true)
196 {
197 char c = read();
198 if (c == ’\n’ || c == ’\r’ || c == -1)
199 break;
200 res += c;
201 }
202
203 return res;
204 }
205
206 inline char eatWhite()
207 {
208 char c = read();
209 while (isSpaceChar(c))
210 c = read();
211 return c;
212 }
213
214 static inline bool isSpaceChar(char c)
215 {
216 return c == ’ ’ || c == ’\n’ || c == ’\r’ || c == ’\t’ || c == -1;
217 }
218 };
219
220
221 int main()
222 {
223 auto t1 = clock();
224
225 std::freopen("../tests/7-18.in", "r", stdin) ; // exec time : 17.859 s
226 //std::freopen("../tests/7-15.in", "r", stdin) ; // exec time : 10.719 s
227 //std::freopen("../tests/7-01.in", "r", stdin) ; // exec time : 12.719 s
228 //std::freopen("../tests/6-07.in", "r", stdin) ; // exec time : 5.438 s
229
230 std::freopen("rectangle.out", "w", stdout) ;
231
232 InputReader inputReader(STDIN_FILENO);
233
234 int n, m;
235 n = inputReader.readInt();
236 m = inputReader.readInt();
237 cerr<<"cerr : "<<n<<" "<<m<<"\n";
238
239 vector<vector<int>> a(n, vector<int>(m));
CAPITOLUL 2. IOI 2019 195
40 s.emplace(0, vector<int>());
41 for (int j = 1; j <= M; j++)
42 {
43 vector<int> curSet;
44 bool initialized = false;
45
46 auto merge = [&](const vector<int>& v)
47 {
48 if (!initialized)
49 {
50 curSet = v;
51 initialized = true;
52 return;
53 }
54
55 vector<int> nCurSet;
56 set_intersection(curSet.begin(), curSet.end(),
57 v.begin(), v.end(), back_inserter(nCurSet));
58 curSet = std::move(nCurSet);
59 };
60
61 while (!s.empty() && G[i][j] >= G[i][s.top().first])
62 {
63 merge(s.top().second);
64 if (G[i][j] > G[i][s.top().first])
65 {
66 s.pop();
67 if (!s.empty())
68 {
69 int l = s.top().first + 1;
70 int r = j-1;
71 if (history[l][r].second != i-1)
72 {
73 history[l][r].first = i;
74 }
75 history[l][r].second = i;
76
77 assert(initialized);
78 int numGood = int(curSet.end() -
79 lower_bound(curSet.begin(),
80 curSet.end(),
81 history[l][r].first));
82 //cerr << numGood << ’\n’;
83 ans += numGood;
84 }
85 }
86 else
87 {
88 s.pop();
89 }
90 }
91
92 if (j == M) break;
93
94 vector<int> heights;
95
96 { // build heights
97 while (!stacks[j].empty() &&
98 G[i+1][j] >= G[stacks[j].top()][j])
99 {
100 if (G[i+1][j] > G[stacks[j].top()][j])
101 {
102 stacks[j].pop();
103 if (!stacks[j].empty())
104 {
105 heights.push_back(stacks[j].top()+1);
106 }
107 }
108 else
109 {
110 stacks[j].pop();
111 }
112 }
113
114 stacks[j].push(i+1);
115 }
CAPITOLUL 2. IOI 2019 197
76 nozoli.pop_back();
77 }
78
79 if(nozoli.size())
80 add_pair(type, lvl, nozoli.back(), i);
81 nozoli.push_back(i);
82 }
83 }
84
85 long long count_rectangles(vector<vector<int> >a)
86 {
87 n = a.size();
88 m = a[0].size();
89
90 for(int i=0;i<n;i++)
91 {
92 vec.clear();
93 for(int j=0;j<m;j++)
94 vec.push_back(a[i][j]);
95 extract_pairs(0,i);
96 }
97
98 for(int i=0;i<=max(n,m);i++)
99 for(int j=0;j<=max(n,m);j++)
100 fp[i][j].clear();
101
102 for(int j=0;j<m;j++)
103 {
104 vec.clear();
105 for(int i=0;i<n;i++)
106 vec.push_back(a[i][j]);
107 extract_pairs(1,j);
108 }
109
110 for(int i=0;i<=max(n,m);i++)
111 for(int j=0;j<=max(n,m);j++)
112 if(sp[0][i][j].size() && sp[1][i][j].size())
113 {
114 sort(sp[0][i][j].begin(), sp[0][i][j].end());
115 sort(sp[1][i][j].begin(), sp[1][i][j].end());
116 // sp[0].X fix sp[1].X moteghaier
117 int p = 0;
118 will_remove.clear();
119 for(int k=0;k<sp[1][i][j].size();k++)
120 {
121 while(p<sp[0][i][j].size() &&
122 sp[0][i][j][p].X <= sp[1][i][j][k].X)
123 {
124 fen_add(sp[0][i][j][p].Y, 1);
125 will_remove.push_back(sp[0][i][j][p].Y);
126 p++;
127 }
128
129 ans += fen_f(sp[1][i][j][k].Y);
130 }
131
132 for(int k=0;k<will_remove.size();k++)
133 fen_add(will_remove[k], -1);
134 }
135
136 return ans;
137 }
138
139 // --------------- start grader ---------------------
140 class InputReader
141 {
142 private:
143 static const int SIZE = 4096;
144
145 int inputFileDescriptor;
146 char buf[SIZE];
147 int curChar;
148 int numChars;
149
150 public:
151
CAPITOLUL 2. IOI 2019 201
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, denite printr-o secvenµ de t 1 puncte p0 , ..., pt dup cum
urmeaz :
Pentru ecare 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-
ne³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 denesc
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, ecare
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 ³iere de intrare în care
vor specicate locaµiile punctelor marcate. Pentru ecare ³ier de intrare, trebuie s înc rcaµi
un ³ier de ie³ire care descrie o linie frânt cu propriet µile cerute.
Pentru ecare ³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 2. IOI 2019 204
6
2 0
2 3
5 3
5 2
4 2
4 4
Restricµii
a M rimea ec rui ³ier de ie³ire (³ier de intrare sau arhiv zip) nu trebuie s dep ³easc
15M B .
Punctare
Pentru ecare test, puteµi obµine maxim 10 puncte. Output-ul unui test va punctat cu 0
puncte dac nu conµine o linie frânt cu propriet µile cerute. Altfel, punctajul va 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: rst 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 2. IOI 2019 205
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 nd 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, nd 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.
4 #include <iostream>
5 #include <algorithm>
6 #include <cstring>
7 #include <string>
8 #include <cmath>
9 #include <cassert>
10 #include <ctime>
11 #include <vector>
12 #include <set>
13 #include <map>
14 #include <unordered_set>
15 #include <unordered_map>
16
17 using namespace std;
18
19 #define pb push_back
20 #define mp make_pair
21 #define fs first
22 #define sc second
23
24 int n;
25 vector <pair <int, int> > input;
26 vector <pair <int, int> > answer;
27 bool last_volatile = false;
28
29 void continue_answer(pair <int, int> point)
30 {
31 if (answer.empty())
32 {
33 answer.pb(point);
34
35 return;
36 }
37
38 if (answer.size() >= 2u)
39 {
40 bool worked = false;
41 int last = (int) answer.size() - 1;
42 int prelast = (int) answer.size() - 2;
43 if (answer[prelast].fs == answer[last].fs)
44 {
45 if ((answer[last].sc - answer[prelast].sc) * 1ll *
46 (point.sc - answer[last].sc) > 0)
47 {
48 answer[last].sc = point.sc;
49 worked = true;
50 }
51 }
52 else
53 {
54 if ((answer[last].fs - answer[prelast].fs) * 1ll *
55 (point.fs - answer[last].fs) > 0)
56 {
57 answer[last].fs = point.fs;
58 worked = true;
59 }
60 }
61
62 if (!worked && last_volatile)
63 {
64 int preprelast = (int) answer.size() - 3;
65 answer[prelast].fs = answer[preprelast].fs;
66 answer[prelast].sc = answer[last].sc;
67 if (answer[prelast].fs == answer[last].fs)
68 {
69 if ((answer[last].sc - answer[prelast].sc) * 1ll *
70 (point.sc - answer[last].sc) > 0)
71 {
72 answer[last].sc = point.sc;
73 }
74 }
75 else
76 {
77 if ((answer[last].fs - answer[prelast].fs) * 1ll *
78 (point.fs - answer[last].fs) > 0)
79 {
CAPITOLUL 2. IOI 2019 207
80 answer[last].fs = point.fs;
81 }
82 }
83 }
84 }
85
86 last_volatile = (point.fs != answer.back().fs && point.sc !=
87 answer.back().sc);
88
89 if (point.fs != answer.back().fs)
90 {
91 answer.pb(mp(point.fs, answer.back().sc));
92 }
93 if (point.sc != answer.back().sc)
94 {
95 answer.pb(point);
96 }
97 }
98
99 void add_spiral(vector <pair <pair <int, int>, pair <int, int> > > spiral)
100 {
101 for (int i = 0; i < (int) spiral.size(); i++)
102 {
103 int lft = spiral[i].fs.fs;
104 int up = spiral[i].fs.sc;
105 int rgt = spiral[i].sc.fs;
106 int down = spiral[i].sc.sc;
107
108 pair <int, int> ldc = mp(input[lft].fs, input[down].sc);
109 pair <int, int> luc = mp(input[lft].fs, input[up].sc);
110 pair <int, int> rdc = mp(input[rgt].fs, input[down].sc);
111 pair <int, int> ruc = mp(input[rgt].fs, input[up].sc);
112
113 if (i == 0)
114 {
115 continue_answer(ldc);
116 continue_answer(luc);
117 continue_answer(ruc);
118 continue_answer(rdc);
119 continue_answer(ldc);
120 }
121 else
122 {
123 answer.back().fs = input[lft].fs;
124 if (input[lft].sc >= answer.back().sc)
125 {
126 continue_answer(luc);
127 continue_answer(ruc);
128 continue_answer(rdc);
129 continue_answer(ldc);
130 }
131 else
132 {
133 continue_answer(ldc);
134 continue_answer(rdc);
135 continue_answer(ruc);
136 continue_answer(luc);
137 }
138 }
139 }
140 }
141
142 void add_chain(vector <pair <int, int> > chain, bool order,
143 bool flip, bool interleave)
144 {
145 if (chain.empty())
146 return;
147 int len = (int) chain.size();
148 if (flip)
149 {
150 for (int i = 0; i < len; i++)
151 {
152 chain[i].fs *= -1;
153 }
154 }
155 if (order)
CAPITOLUL 2. IOI 2019 208
156 {
157 for (int i = 0; i < len; i++)
158 {
159 chain[i].sc *= -1;
160 }
161 }
162 sort(chain.begin(), chain.end());
163 if (flip)
164 {
165 for (int i = 0; i < len; i++)
166 {
167 chain[i].fs *= -1;
168 }
169 }
170 if (order)
171 {
172 for (int i = 0; i < len; i++)
173 {
174 chain[i].sc *= -1;
175 }
176 }
177
178 continue_answer(chain[0]);
179 for (int i = 1; i < len; i++)
180 {
181 if (i % 2 xor interleave)
182 {
183 continue_answer(mp(chain[i].fs, chain[i - 1].sc));
184 }
185 else
186 {
187 continue_answer(mp(chain[i - 1].fs, chain[i].sc));
188 }
189 }
190 if (len > 1)
191 {
192 continue_answer(chain.back());
193 }
194 }
195
196 void finalize()
197 {
198 cerr << n << ’ ’ << answer.size() - 1 << ’ ’ << answer.size() - 1 - n << ’\n’;
199 cout << answer.size()-1 << ’\n’;
200 for (int i = 1; i < (int) answer.size(); i++)
201 {
202 cout << answer[i].fs << ’ ’ << answer[i].sc << ’\n’;
203 }
204 }
205
206 int main ()
207 {
208 cin >> n;
209
210 for (int i = 0; i < n; i++)
211 {
212 int x, y;
213 cin >> x >> y;
214 input.pb(mp(x, y));
215 }
216
217 vector <pair <int, int> > chain1, chain2;
218 vector <pair <pair <int, int>, pair <int, int> > > spiral;
219 set <pair <int, int> > xs;
220 set <pair <int, int> > ys;
221 vector <bool> used(n, false);
222
223 for (int i = 0; i < n; i++)
224 {
225 xs.insert(mp(input[i].fs, i));
226 ys.insert(mp(input[i].sc, i));
227 }
228
229 while (true)
230 {
231 int lft = -1;
CAPITOLUL 2. IOI 2019 209
32 answer.pb(point);
33
34 return;
35 }
36
37 if (answer.size() >= 2u)
38 {
39 bool worked = false;
40 int last = (int) answer.size() - 1;
41 int prelast = (int) answer.size() - 2;
42 if (answer[prelast].fs == answer[last].fs)
43 {
44 if ((answer[last].sc - answer[prelast].sc) * 1ll *
45 (point.sc - answer[last].sc) > 0)
46 {
47 answer[last].sc = point.sc;
48 worked = true;
49 }
50 }
51 else
52 {
53 if ((answer[last].fs - answer[prelast].fs) * 1ll *
54 (point.fs - answer[last].fs) > 0)
55 {
56 answer[last].fs = point.fs;
57 worked = true;
58 }
59 }
60
61 if (!worked && last_volatile)
62 {
63 int preprelast = (int) answer.size() - 3;
64 answer[prelast].fs = answer[preprelast].fs;
65 answer[prelast].sc = answer[last].sc;
66 if (answer[prelast].fs == answer[last].fs)
67 {
68 if ((answer[last].sc - answer[prelast].sc) * 1ll *
69 (point.sc - answer[last].sc) > 0)
70 {
71 answer[last].sc = point.sc;
72 }
73 }
74 else
75 {
76 if ((answer[last].fs - answer[prelast].fs) * 1ll *
77 (point.fs - answer[last].fs) > 0)
78 {
79 answer[last].fs = point.fs;
80 }
81 }
82 }
83 }
84
85 last_volatile = (point.fs != answer.back().fs && point.sc !=
86 answer.back().sc);
87
88 if (point.fs != answer.back().fs)
89 {
90 answer.pb(mp(point.fs, answer.back().sc));
91 }
92 if (point.sc != answer.back().sc)
93 {
94 answer.pb(point);
95 }
96 }
97
98 void add_spiral(vector <pair <pair <int, int>, pair <int, int> > > spiral)
99 {
100 for (int i = 0; i < (int) spiral.size(); i++)
101 {
102 int lft = spiral[i].fs.fs;
103 int up = spiral[i].fs.sc;
104 int rgt = spiral[i].sc.fs;
105 int down = spiral[i].sc.sc;
106
107 pair <int, int> ldc = mp(input[lft].fs, input[down].sc);
CAPITOLUL 2. IOI 2019 212
184 else
185 {
186 continue_answer(mp(chain[i - 1].fs, chain[i].sc));
187 }
188 }
189 if (len > 1)
190 {
191 continue_answer(chain.back());
192 }
193 }
194
195 void finalize()
196 {
197 cerr << "cerr : "<<n << ’ ’ << answer.size() - 1
198 << ’ ’ << answer.size() - 1 - n << ’\n’;
199 cout << answer.size()-1 << ’\n’;
200 for (int i = 1; i < (int) answer.size(); i++)
201 {
202 cout << answer[i].fs << ’ ’ << answer[i].sc << ’\n’;
203 }
204 }
205
206 int main ()
207 {
208 auto t1 = clock();
209
210 std::freopen("../tests/10.in", "r", stdin) ; // execution time : 15.805 s
211 //std::freopen("../tests/04.in", "r", stdin) ; // execution time : 7.761 s
212 //std::freopen("../tests/03.in", "r", stdin) ; // execution time : 0.875 s
213 //std::freopen("../tests/00.in", "r", stdin) ; // execution time : 0.031 s
214
215
216 std::freopen("line.out", "w", stdout) ;
217
218 cin >> n;
219
220 cerr<<"cerr : "<<n<<"\n";
221
222 for (int i = 0; i < n; i++)
223 {
224 int x, y;
225 cin >> x >> y;
226 input.pb(mp(x, y));
227 }
228
229 auto t2 = clock();
230
231 vector <pair <int, int> > chain1, chain2;
232 vector <pair <pair <int, int>, pair <int, int> > > spiral;
233 set <pair <int, int> > xs;
234 set <pair <int, int> > ys;
235 vector <bool> used(n, false);
236
237 for (int i = 0; i < n; i++)
238 {
239 xs.insert(mp(input[i].fs, i));
240 ys.insert(mp(input[i].sc, i));
241 }
242
243 while (true)
244 {
245 int lft = -1;
246 while (!xs.empty() && used[xs.begin()->sc])
247 {
248 xs.erase(xs.begin());
249 }
250 if (!xs.empty())
251 {
252 lft = xs.begin()->sc;
253 }
254
255 int rgt = -1;
256 while (!xs.empty() && used[xs.rbegin()->sc])
257 {
258 xs.erase( *xs.rbegin());
259 }
CAPITOLUL 2. IOI 2019 214
260 if (!xs.empty())
261 {
262 rgt = xs.rbegin()->sc;
263 }
264
265 int down = -1;
266 while (!ys.empty() && used[ys.begin()->sc])
267 {
268 ys.erase(ys.begin());
269 }
270 if (!ys.empty())
271 {
272 down = ys.begin()->sc;
273 }
274
275 int up = -1;
276 while (!ys.empty() && used[ys.rbegin()->sc])
277 {
278 ys.erase( *ys.rbegin());
279 }
280 if (!ys.empty())
281 {
282 up = ys.rbegin()->sc;
283 }
284
285 if (lft == -1 || rgt == -1 || down == -1 || up == -1)
286 {
287 break;
288 }
289
290 if (lft == down)
291 {
292 chain1.pb(input[lft]);
293 used[lft] = true;
294 continue;
295 }
296 if (lft == up)
297 {
298 chain2.pb(input[lft]);
299 used[lft] = true;
300 continue;
301 }
302 if (rgt == down)
303 {
304 chain2.pb(input[rgt]);
305 used[rgt] = true;
306 continue;
307 }
308 if (rgt == up)
309 {
310 chain1.pb(input[rgt]);
311 used[rgt] = true;
312 continue;
313 }
314 spiral.pb(mp(mp(lft, up), mp(rgt, down)));
315 used[lft] = true;
316 used[rgt] = true;
317 used[down] = true;
318 used[up] = true;
319 }
320
321 reverse(spiral.begin(), spiral.end());
322 vector <pair <int, int> > best_answer;
323 for (int flip1 = 0; flip1 < 8; flip1++)
324 {
325 for (int flip2 = 0; flip2 < 8; flip2++)
326 {
327 vector <int> parts = {0, 1, 2};
328 do
329 {
330 answer.clear();
331 last_volatile = false;
332 continue_answer(mp(0, 0));
333 for (int i = 0; i < (int) parts.size(); i++)
334 {
335 if (parts[i] == 0)
CAPITOLUL 2. IOI 2019 215
336 {
337 add_spiral(spiral);
338 }
339 else
340 if (parts[i] == 1)
341 {
342 add_chain(chain1, flip1 >> 2,
343 (flip1 >> 1) & 1, flip1 & 1);
344 }
345 else
346 {
347 add_chain(chain2, flip2 >> 2,
348 (flip2 >> 1) & 1, flip2 & 1);
349 }
350 }
351 if (best_answer.empty() ||
352 answer.size() < best_answer.size())
353 {
354 best_answer = answer;
355 }
356 } while (next_permutation(parts.begin(), parts.end()));
357 }
358 }
359
360 answer = best_answer;
361
362 auto t3 = clock();
363
364 finalize();
365
366 auto t4 = clock();
367
368 // reset console output
369 freopen("CON", "w", stdout);
370
371 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
372 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
373 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
374
375 return 0;
376 }
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 consecu-
tivi î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 celule care
stocheaz e pixeli, e 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 e 1 dac distanµa dintre cei doi pixeli
negri este exact K , altfel ie³irea este 0.
Detalii de implementare
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
Restricµii
Subtaskuri
Exemplu de grader
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 dierence
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 dierences 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 denition 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.
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.
CAPITOLUL 2. IOI 2019 219
17 {
18 return a <= b && b <= c;
19 }
20
21 [[noreturn]] static inline void error(string message)
22 {
23 printf("%s\n", message.c_str());
24 exit(0);
25 }
26
27 class InstructionNetwork
28 {
29
30 struct Instruction
31 {
32 int type;
33 vector<int> input_indexes;
34
35 inline Instruction(int _type, const vector<int>& _input_indexes):
36 type(_type), input_indexes(_input_indexes) { }
37
38 inline int apply(int a, int b) const
39 {
40 switch (type)
41 {
42 case _AND:
43 return a & b;
44 case _OR:
45 return a | b;
46 case _XOR:
47 return a ^ b;
48 default:
49 return 0;
50 }
51 }
52
53 inline int compute(const vector<int>& memory_cells) const
54 {
55 int r = memory_cells[input_indexes[0]];
56 if (type == _NOT)
57 return 1 - r;
58 for (int j = 1; j < (int)input_indexes.size(); j++)
59 r = apply(r, memory_cells[input_indexes[j]]);
60 return r;
61 }
62 };
63
64 int input_size;
65 int total_inputs;
66 vector<Instruction> instructions;
67
68 public:
69
70 inline void init(int _input_size)
71 {
72 this->input_size = _input_size;
73 this->total_inputs = 0;
74 this->instructions.clear();
75 }
76
77 inline int add_instruction(int type, const vector<int>& input_indexes)
78 {
79 if (input_indexes.size() == 0)
80 error("Instruction with no inputs");
81
82 if (instructions.size() + 1 > MAX_INSTRUCTIONS)
83 error("Too many instructions");
84
85 if (total_inputs + input_indexes.size() > MAX_INPUTS)
86 error("Too many inputs");
87
88 instructions.emplace_back(type, input_indexes);
89 total_inputs += input_indexes.size();
90 int new_index = input_size + (int)instructions.size() - 1;
91
92 for (int input_index : input_indexes)
CAPITOLUL 2. IOI 2019 221
60 {
61 for (int i = 0; i < H + W - 1; i++)
62 {
63 vector<int> cells = diagonal(H, W, i, D);
64 ors.emplace_back(OR(cells));
65 xors.emplace_back(XOR(cells));
66 }
67 }
68
69 int find_pair(const vector<int> &ors, const vector<int> &xors, int maxDistance)
70 {
71 int n = maxDistance + 1;
72 vector<int> curOrs(n), curXors(n), results;
73 for (int i = 0; i < (int)ors.size(); i++)
74 {
75 curOrs[i % n] = ors[i];
76 curXors[i % n] = xors[i];
77 if (i >= maxDistance)
78 {
79 results.emplace_back(AND_NOT(OR(curOrs), XOR(curXors)));
80 }
81 }
82 return OR(results);
83 }
84
85 void construct_network(int H, int W, int K)
86 {
87 vector<int> orsA, xorsA, orsB, xorsB;
88 collect_diagonals(H, W, true, orsA, xorsA);
89 collect_diagonals(H, W, false, orsB, xorsB);
90 AND_NOT(AND(find_pair(orsA, xorsA, K),
91 find_pair(orsB, xorsB, K)),
92 AND(find_pair(orsA, xorsA, K - 1),
93 find_pair(orsB, xorsB, K - 1)));
94 }
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 a 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 , aat
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.
Î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.
CAPITOLUL 2. IOI 2019 224
Detalii de implementare
Trebuie s implementaµi urm toarea funcµie. Aceasta va apelat de c tre grader câte o dat
pentru ecare 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
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 nd 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
eciently. 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).
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.
CAPITOLUL 2. IOI 2019 226
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 rst 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 rst 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. Specically, 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 rst 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.
121 r[i] = a;
122 if (a < b)
123 {
124 l.push_back(a);
125 r.push_back(b);
126 y.push_back(y[i]);
127 }
128 }
129 else
130 {
131 assert(x == a);
132 r[i] = b;
133 }
134 if (q > b)
135 {
136 l.push_back(b);
137 r.push_back(q);
138 y.push_back(y[i]);
139 }
140 else
141 {
142 assert(q == b);
143 }
144 }
145 }
146
147 long long min_distance(vector<int> x, vector<int> h,
148 vector<int> l, vector<int> r,
149 vector<int> y, int s, int g)
150 {
151 if (s == g)
152 return 0;
153 int n = x.size();
154
155 break_segments(l, r, y, s, h);
156 break_segments(l, r, y, g, h);
157 int m = l.size();
158
159 for (int i = 0; i < m; i++)
160 {
161 last_x[i] = last_vertex[i] = -1;
162 adds[l[i]].push_back(pii(y[i], i));
163 removes[r[i]].push_back(pii(y[i], i));
164 }
165 int sv = -1, gv = -1;
166 long long res = 0;
167 for (int i = 0; i < n; i++)
168 {
169 sort(adds[i].begin(), adds[i].end());
170 for (int j = 0; j < (int)adds[i].size(); j++)
171 {
172 int v = make_vertex(adds[i][j].second, x[i]);
173 sit it = walks.lower_bound(adds[i][j]);
174 if (it != walks.begin())
175 {
176 it--;
177 int u = make_vertex(it->second, x[i]);
178 add_edge(u, v, adds[i][j].first - it->first);
179 }
180 walks.insert(adds[i][j]);
181 }
182 if (i == s)
183 {
184 if (walks.empty() || walks.begin()->first > h[i])
185 return -1;
186 sv = make_vertex(walks.begin()->second, x[i]);
187 res += walks.begin()->first;
188 }
189 if (i == g)
190 {
191 if (walks.empty() || walks.begin()->first > h[i])
192 return -1;
193 gv = make_vertex(walks.begin()->second, x[i]);
194 res += walks.begin()->first;
195 }
196 sort(removes[i].begin(), removes[i].end(), greater<pii>());
CAPITOLUL 2. IOI 2019 230
51 int u = edges[v][i].first;
52 int w = edges[v][i].second;
53 if (dist[u] > dist[v] + w)
54 {
55 dij.erase(pli(dist[u], u));
56 dist[u] = dist[v] + w;
57 dij.insert(pli(dist[u], u));
58 }
59 }
60 }
61 return -1;
62 }
63
64 void add_edge(int u, int v, int w)
65 {
66 edges[u].push_back(pii(v, w));
67 edges[v].push_back(pii(u, w));
68 }
69
70 int make_vertex(int walk, int x)
71 {
72 if (last_x[walk] == x)
73 return last_vertex[walk];
74 int cur = vcnt++;
75 if (last_vertex[walk] != -1)
76 add_edge(last_vertex[walk], cur, x - last_x[walk]);
77 last_x[walk] = x;
78 last_vertex[walk] = cur;
79 return cur;
80 }
81
82 void break_segments(vector<int> &l, vector<int> &r,
83 vector<int> &y, int s, vector<int> &h)
84 {
85 vector<int> heights = h;
86 sort(heights.begin(), heights.end());
87 heights.resize(unique(heights.begin(),
88 heights.end()) - heights.begin());
89 for (int i = 0; i < (int)heights.size(); i++)
90 {
91 last_height[i] = -1;
92 first_height[i] = h.size() + 1;
93 }
94
95 for (int i = 0; i < (int)h.size(); i++)
96 {
97 int idx = lower_bound(heights.begin(), heights.end(),
98 h[i]) - heights.begin();
99 assert(idx < (int)heights.size());
100 if (i <= s)
101 last_height[idx] = max(last_height[idx], i);
102 if (i >= s)
103 first_height[idx] = min(first_height[idx], i);
104 }
105
106 for (int i = (int)heights.size() - 2; i >= 0; i--)
107 {
108 last_height[i] = max(last_height[i], last_height[i + 1]);
109 first_height[i] = min(first_height[i], first_height[i + 1]);
110 }
111
112 for (int i = 0; i < (int)l.size(); i++)
113 if (l[i] < s && r[i] > s)
114 {
115 int idx = lower_bound(heights.begin(), heights.end(),
116 y[i]) - heights.begin();
117 assert(idx < (int)heights.size());
118 int x = l[i];
119 int a = last_height[idx];
120 int b = first_height[idx];
121 int q = r[i];
122
123 assert(a != -1);
124 assert(b != (int)h.size() + 1);
125
126 if (x < a)
CAPITOLUL 2. IOI 2019 232
127 {
128 r[i] = a;
129 if (a < b)
130 {
131 l.push_back(a);
132 r.push_back(b);
133 y.push_back(y[i]);
134 }
135 }
136 else
137 {
138 assert(x == a);
139 r[i] = b;
140 }
141 if (q > b)
142 {
143 l.push_back(b);
144 r.push_back(q);
145 y.push_back(y[i]);
146 }
147 else
148 {
149 assert(q == b);
150 }
151 }
152 }
153
154 long long min_distance(vector<int> x, vector<int> h,
155 vector<int> l, vector<int> r,
156 vector<int> y, int s, int g)
157 {
158 if (s == g)
159 return 0;
160 int n = x.size();
161
162 break_segments(l, r, y, s, h);
163 break_segments(l, r, y, g, h);
164 int m = l.size();
165
166 for (int i = 0; i < m; i++)
167 {
168 last_x[i] = last_vertex[i] = -1;
169 adds[l[i]].push_back(pii(y[i], i));
170 removes[r[i]].push_back(pii(y[i], i));
171 }
172
173 int sv = -1, gv = -1;
174 long long res = 0;
175 for (int i = 0; i < n; i++)
176 {
177 sort(adds[i].begin(), adds[i].end());
178 for (int j = 0; j < (int)adds[i].size(); j++)
179 {
180 int v = make_vertex(adds[i][j].second, x[i]);
181 sit it = walks.lower_bound(adds[i][j]);
182 if (it != walks.begin())
183 {
184 it--;
185 int u = make_vertex(it->second, x[i]);
186 add_edge(u, v, adds[i][j].first - it->first);
187 }
188 walks.insert(adds[i][j]);
189 }
190
191 if (i == s)
192 {
193 if (walks.empty() || walks.begin()->first > h[i])
194 return -1;
195 sv = make_vertex(walks.begin()->second, x[i]);
196 res += walks.begin()->first;
197 }
198
199 if (i == g)
200 {
201 if (walks.empty() || walks.begin()->first > h[i])
202 return -1;
CAPITOLUL 2. IOI 2019 233
279 return 0;
280 }
281 //-------------- end grader ------------------
70 ll i;
71 scanf("%" SCNd64, &i);
72 return i;
73 }
74
75 void printSpace()
76 {
77 printf(" ");
78 }
79
80 void printEoln()
81 {
82 printf("\n");
83 }
84
85 void print(ll x, int suc = 1)
86 {
87 printf("%" PRId64, x);
88 if (suc == 1)
89 printEoln();
90 if (suc == 2)
91 printSpace();
92 }
93
94 string readString()
95 {
96 static char buf[3341000];
97 scanf("%s", buf);
98 return string(buf);
99 }
100
101 char *readCharArray()
102 {
103 static char buf[3341000];
104 static int bufUsed = 0;
105 char *ret = buf + bufUsed;
106 scanf("%s", ret);
107 bufUsed += strlen(ret) + 1;
108 return ret;
109 }
110
111 template <class T, class U>
112 void chmax(T &a, U b)
113 {
114 if (a < b)
115 a = b;
116 }
117
118 template <class T, class U>
119 void chmin(T &a, U b)
120 {
121 if (b < a)
122 a = b;
123 }
124
125 template <class T>
126 T Sq(const T &t)
127 {
128 return t * t;
129 }
130
131 const ll infLL = LLONG_MAX / 3;
132
133 #ifdef int
134 const int inf = infLL;
135 #else
136 const int inf = INT_MAX / 2 - 100;
137 #endif
138
139 namespace Subtask4
140 {
141 ll Solve(vi x, vi h, vi l, vi r, vi y, int s, int g)
142 {
143 int n = x.size();
144 REP(k, 2)
145 {
CAPITOLUL 2. IOI 2019 236
146 int w = k == 0 ? s : g;
147 vector<pi> p{pi(h[w], w)}, q{pi(h[w], w)};
148
149 for (int i = w - 1; i >= 0; i--)
150 if (h[i] > p.back().first)
151 p.EB(h[i], i);
152
153 for (int i = w + 1; i < n; i++)
154 if (h[i] > q.back().first)
155 q.EB(h[i], i);
156
157 vi ll, rr, yy;
158 REP(i, l.size())
159 {
160 if (l[i] < w && w < r[i])
161 {
162 int a, b;
163 {
164 auto itr = lower_bound(ALL(p), pi(y[i], -1));
165 assert(itr != p.end());
166 a = itr->second;
167 }
168 {
169 auto itr = lower_bound(ALL(q), pi(y[i], -1));
170 assert(itr != q.end());
171 b = itr->second;
172 }
173 if (l[i] < a)
174 {
175 ll.PB(l[i]);
176 rr.PB(a);
177 yy.PB(y[i]);
178 }
179 if (a < b)
180 {
181 ll.PB(a);
182 rr.PB(b);
183 yy.PB(y[i]);
184 }
185 if (b < r[i])
186 {
187 ll.PB(b);
188 rr.PB(r[i]);
189 yy.PB(y[i]);
190 }
191 }
192 else
193 {
194 ll.PB(l[i]);
195 rr.PB(r[i]);
196 yy.PB(y[i]);
197 }
198 }
199 l = ll;
200 r = rr;
201 y = yy;
202 }
203
204 int m = l.size();
205
206 vector<pi> posYX{pi(0, x[s]), pi(0, x[g])};
207 {
208 vector<tuple<int, int, int>> xty;
209 REP(i, m)
210 {
211 xty.EB(x[l[i]], 0, y[i]);
212 xty.EB(x[r[i]], 1, -y[i]);
213 }
214
215 sort(ALL(xty));
216
217 multiset<int> ys;
218 for (auto q : xty)
219 {
220 int j=get<0>(q), t=get<1>(q), i = get<2>(q) * (t == 0 ? 1 : -1);
221 posYX.EB(i, j);
CAPITOLUL 2. IOI 2019 237
298 pq.pop();
299 if (dist[v] != d)
300 continue;
301 for (auto e : graph[v])
302 Reach(e.first, dist[v] + e.second);
303 }
304
305 return dist[Idx(0, x[g])] == infLL ? -1 : dist[Idx(0, x[g])];
306 }
307 } // namespace Subtask4
308
309 long long min_distance(std::vector<int> X, std::vector<int> H,
310 std::vector<int> L, std::vector<int> R,
311 std::vector<int> Y, int S, int G)
312 {
313 return Subtask4::Solve(X, H, L, R, Y, S, G);
314 }
315
316 //-------------- start grader ------------------
317
318 int main()
319 {
320 std::freopen("../tests/5-30.in", "r", stdin) ;
321 std::freopen("walking.out", "w", stdout) ;
322
323 auto t1 = clock();
324
325 int n, m;
326 assert(2 == scanf("%d%d", &n, &m));
327 cerr<<"cerr : "<<n<<" "<<m<<"\n";
328
329 vector<int> x(n), h(n);
330 for (int i = 0; i < n; i++)
331 assert(2 == scanf("%d%d", &x[i], &h[i]));
332
333 vector<int> l(m), r(m), y(m);
334 for (int i = 0; i < m; i++)
335 assert(3 == scanf("%d%d%d", &l[i], &r[i], &y[i]));
336 int s, g;
337 assert(2 == scanf("%d%d", &s, &g));
338 fclose(stdin);
339
340 auto t2 = clock();
341
342 long long result = min_distance(x, h, l, r, y, s, g);
343
344 auto t3 = clock();
345
346 printf("%lld\n", result);
347 fclose(stdout);
348
349 auto t4 = clock();
350
351 // reset console output
352 freopen("CON", "w", stdout);
353
354 std::cout <<"result = "<<result<<’\n’<<’\n’;
355
356 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
357 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
358 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
359
360 return 0;
361 }
362 //-------------- end grader ------------------
8 #include <ctime>
9 #include <cassert>
10
11 #define pb push_back
12 #define mp make_pair
13
14 using namespace std;
15
16 const int maxn = 1000000 + 10;
17 const long long inf = 1e18;
18
19 int n, m, X[maxn], Y[maxn], H[maxn], L[maxn], R[maxn],
20 a[maxn], b[maxn], node, y_map[maxn];
21
22 vector<int> neiL[maxn], neiR[maxn];
23
24 long long dis[maxn];
25
26 vector<pair<int, long long>> adj[maxn];
27 map<pair<int, int>, int> nodes;
28 vector<int> all_y;
29
30 void devide(int idx)
31 {
32 memset(a, -1, sizeof(a));
33 memset(b, -1, sizeof(b));
34
35 vector<pair<pair<int, int>, int>> sky;
36 vector<pair<int, int>> st;
37
38 st.pb(mp(H[idx], idx));
39 for (int i = idx - 1; i >= 0; i--)
40 {
41 if (H[i] > st.back().first)
42 st.push_back(mp(H[i], i));
43 for (int j = 0; j < neiL[i].size(); j++)
44 {
45 int cur = neiL[i][j];
46 if (R[cur] > idx)
47 {
48 int pos = upper_bound(st.begin(), st.end(),
49 mp(Y[cur], -1)) - st.begin();
50 a[cur] = st[pos].second;
51 }
52 }
53 }
54 st.clear();
55 st.pb(mp(H[idx], idx));
56 for (int i = idx + 1; i < n; i++)
57 {
58 if (H[i] > st.back().first)
59 st.push_back(mp(H[i], i));
60 for (int j = 0; j < neiR[i].size(); j++)
61 {
62 int cur = neiR[i][j];
63 if (L[cur] < idx)
64 {
65 int pos = upper_bound(st.begin(), st.end(),
66 mp(Y[cur], -1)) - st.begin();
67 b[cur] = st[pos].second;
68 }
69 }
70 }
71
72 for (int i = 0; i < m; i++)
73 {
74 if (a[i] != -1)
75 {
76 if (a[i] != L[i])
77 sky.pb(mp(mp(L[i], a[i]), Y[i]));
78 if (a[i] != b[i])
79 sky.pb(mp(mp(a[i], b[i]), Y[i]));
80 if (b[i] != R[i])
81 sky.pb(mp(mp(b[i], R[i]), Y[i]));
82 }
83 else
CAPITOLUL 2. IOI 2019 240
160 {
161 set<int> line;
162 line.insert(0);
163 set<int>::iterator it;
164 map<int, int> st;
165 vector<int> set_res;
166
167 memset(y_map, -1, sizeof(y_map));
168
169 for (int i = 0; i < n; i++)
170 {
171 for (int j = 0; j < neiL[i].size(); j++)
172 {
173 int cur = neiL[i][j];
174 line.insert(-Y[cur]);
175 }
176
177 for (int j = 0; j < neiL[i].size(); j++)
178 {
179 int cur = neiL[i][j];
180 it = line.upper_bound(-Y[cur]);
181 int y2 = Y[cur];
182 int y1 = -( *it);
183 int y2_id = lower_bound(all_y.begin(), all_y.end(), y2) -
184 all_y.begin() + 1;
185 int y1_id = lower_bound(all_y.begin(), all_y.end(), y1) -
186 all_y.begin() + 1;
187 set_res.pb(y1_id);
188 set_res.pb(y2_id);
189 add_edge(X[i], y1, X[i], y2);
190 if (y_map[y1_id] != -1 && y1 != 0)
191 {
192 add_edge(X[i], y1, y_map[y1_id], y1);
193 }
194 }
195
196 for (int j = 0; j < neiR[i].size(); j++)
197 {
198 int cur = neiR[i][j];
199 it = line.upper_bound(-Y[cur]);
200 int y2 = Y[cur];
201 int y1 = -( *it);
202 int y2_id = lower_bound(all_y.begin(), all_y.end(), y2) -
203 all_y.begin() + 1;
204 int y1_id = lower_bound(all_y.begin(), all_y.end(), y1) -
205 all_y.begin() + 1;
206 set_res.pb(y1_id);
207 set_res.pb(y2_id);
208 add_edge(X[i], y1, X[i], y2);
209 add_edge(X[i], y2, y_map[y2_id], y2);
210 if (y_map[y1_id] != -1 && y1 != 0)
211 {
212 add_edge(X[i], y1, y_map[y1_id], y1);
213 }
214 }
215
216 for (int j = 0; j < set_res.size(); j++)
217 y_map[set_res[j]] = X[i];
218 set_res.clear();
219
220 for (int j = 0; j < neiR[i].size(); j++)
221 {
222 int cur = neiR[i][j];
223 int y2 = lower_bound(all_y.begin(), all_y.end(), Y[cur]) -
224 all_y.begin() + 1;
225 y_map[y2] = -1;
226 line.erase(-Y[cur]);
227 }
228
229 for (int j = 0; j < neiL[i].size(); j++)
230 {
231 int cur = neiL[i][j];
232 int y2 = lower_bound(all_y.begin(), all_y.end(), Y[cur]) -
233 all_y.begin() + 1;
234 y_map[y2] = X[i];
235 line.insert(-Y[cur]);
CAPITOLUL 2. IOI 2019 242
236 }
237 }
238 }
239
240 bool cmp(pair<int, pair<int, int> > aa, pair<int, pair<int, int> > bb)
241 {
242 if(aa.first < bb.first)
243 return true;
244 if(aa.first > bb.first)
245 return false;
246 return aa.second.first < bb.second.first;
247
248 }
249
250 void init()
251 {
252 vector<pair<int, pair<int, int> > > tmp, nw;
253 for(int i = 0; i < m; i++)
254 tmp.push_back(mp(Y[i], mp(L[i], R[i])));
255
256 sort(tmp.begin(), tmp.end(), cmp);
257
258 for(int i = 0; i < m; i++)
259 {
260 if(tmp[i].second.first == tmp[i].second.second) continue;
261 int j = i;
262 int hei = tmp[i].first;
263 int lo = tmp[i].second.first;
264 int hi = tmp[i].second.second;
265 while(tmp[j].first == hei && tmp[j].second.first <= hi &&
266 tmp[j].second.first >= lo)
267 {
268 hi = max(hi, tmp[j].second.second);
269 j++;
270 }
271 nw.push_back(mp(hei, mp(lo, hi)));
272 i = j - 1;
273 }
274
275 m = nw.size();
276 for (int i = 0; i < m; i++)
277 {
278 L[i] = nw[i].second.first;
279 R[i] = nw[i].second.second;
280 Y[i] = nw[i].first;
281 neiL[L[i]].pb(i);
282 neiR[R[i]].pb(i);
283 }
284
285 }
286
287 long long min_distance(vector<int> XX, vector<int> HH, vector<int> LL,
288 vector<int> RR, vector<int> YY, int S, int G)
289 {
290 n = XX.size();
291 m = LL.size();
292 for (int i = 0; i < n; i++)
293 {
294 X[i] = XX[i];
295 H[i] = HH[i];
296 }
297
298 for (int i = 0; i < m; i++)
299 {
300 L[i] = LL[i];
301 R[i] = RR[i];
302 Y[i] = YY[i];
303 all_y.push_back(Y[i]);
304 }
305
306 init();
307 all_y.push_back(0);
308
309 sort(all_y.begin(), all_y.end());
310
311 all_y.resize(unique(all_y.begin(), all_y.end()) - all_y.begin());
CAPITOLUL 2. IOI 2019 243
312 devide(S);
313 devide(G);
314 build_graph();
315 return dijkstra(add_map(X[S], 0), add_map(X[G], 0));
316 }
317
318 //-------------- start grader ------------------
319
320 int main()
321 {
322 std::freopen("../tests/5-30.in", "r", stdin) ;
323 std::freopen("walking.out", "w", stdout) ;
324
325 auto t1 = clock();
326
327 int n, m;
328 assert(2 == scanf("%d%d", &n, &m));
329 cerr<<"cerr : "<<n<<" "<<m<<"\n";
330
331 vector<int> x(n), h(n);
332 for (int i = 0; i < n; i++)
333 assert(2 == scanf("%d%d", &x[i], &h[i]));
334
335 vector<int> l(m), r(m), y(m);
336 for (int i = 0; i < m; i++)
337 assert(3 == scanf("%d%d%d", &l[i], &r[i], &y[i]));
338 int s, g;
339 assert(2 == scanf("%d%d", &s, &g));
340 fclose(stdin);
341
342 auto t2 = clock();
343
344 long long result = min_distance(x, h, l, r, y, s, g);
345
346 auto t3 = clock();
347
348 printf("%lld\n", result);
349 fclose(stdout);
350
351 auto t4 = clock();
352
353 // reset console output
354 freopen("CON", "w", stdout);
355
356 std::cout <<"result = "<<result<<’\n’<<’\n’;
357
358 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
359 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
360 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
361
362 return 0;
363 }
364 //-------------- end grader ------------------
96
97 template<class T> void prContain(const T& x)
98 {
99 pr("{");
100 bool fst = 1;
101 for (const auto& a: x)
102 pr(!fst?", ":"",a), fst = 0; // const needed for vector<bool>
103 pr("}");
104 }
105
106 template<class T, size_t SZ> void pr(const array<T,SZ>& x)
107 {
108 prContain(x);
109 }
110
111 template<class T> void pr(const vector<T>& x) { prContain(x); }
112 template<class T> void pr(const set<T>& x) { prContain(x); }
113
114 template<class T1, class T2> void pr(const map<T1,T2>& x)
115 {
116 prContain(x);
117 }
118
119 void ps() { pr("\n"); }
120
121 template<class Arg> void ps(const Arg& first)
122 {
123 pr(first); ps(); // no space at end of line
124 }
125
126 template<class Arg, class... Args> void ps(const Arg& first,
127 const Args&... rest)
128 {
129 pr(first," "); ps(rest...); // print w/ spaces
130 }
131 }
132
133 using namespace output;
134
135 namespace io
136 {
137 void setIn(string s) { freopen(s.c_str(),"r",stdin); }
138 void setOut(string s) { freopen(s.c_str(),"w",stdout); }
139
140 void setIO(string s = "")
141 {
142 ios_base::sync_with_stdio(0); cin.tie(0); // fast I/O
143 if (sz(s)) { setIn(s+".in"), setOut(s+".out"); } // for USACO
144 }
145 }
146
147 using namespace io;
148
149 template<class T> T invGeneral(T a, T b)
150 {
151 a %= b; if (a == 0) return b == 1 ? 0 : -1;
152 T x = invGeneral(b,a);
153 return x == -1 ? -1 : ((1-(ll)b*x)/a+b)%b;
154 }
155
156 template<class T> struct modular
157 {
158 T val;
159 explicit operator T() const { return val; }
160 modular() { val = 0; }
161
162 modular(const ll& v)
163 {
164 val = (-MOD <= v && v <= MOD) ? v : v % MOD;
165 if (val < 0) val += MOD;
166 }
167
168 friend void pr(const modular& a) { pr(a.val); }
169 friend void re(modular& a) { ll x; re(x); a = modular(x); }
170
171 friend bool operator==(const modular& a, const modular& b)
CAPITOLUL 2. IOI 2019 246
172 {
173 return a.val == b.val;
174 }
175
176 friend bool operator!=(const modular& a, const modular& b)
177 {
178 return !(a == b);
179 }
180
181 friend bool operator<(const modular& a, const modular& b)
182 {
183 return a.val < b.val;
184 }
185
186 modular operator-() const { return modular(-val); }
187
188 modular& operator+=(const modular& m)
189 {
190 if ((val += m.val) >= MOD)
191 val -= MOD;
192 return *this;
193 }
194
195 modular& operator-=(const modular& m)
196 {
197 if ((val -= m.val) < 0)
198 val += MOD;
199 return *this;
200 }
201
202 modular& operator*=(const modular& m)
203 {
204 val = (ll)val*m.val%MOD;
205 return *this;
206 }
207
208 friend modular pow(modular a, ll p)
209 {
210 modular ans = 1;
211 for (; p; p /= 2, a *= a)
212 if (p&1)
213 ans *= a;
214 return ans;
215 }
216
217 friend modular inv(const modular& a)
218 {
219 auto i = invGeneral(a.val,MOD); assert(i != -1);
220 return i;
221 } // equivalent to return exp(b,MOD-2) if MOD is prime
222
223 modular& operator/=(const modular& m) { return ( *this) *= inv(m); }
224
225 friend modular operator+(modular a, const modular& b) {return a += b;}
226 friend modular operator-(modular a, const modular& b) {return a -= b;}
227 friend modular operator*(modular a, const modular& b) {return a *= b;}
228
229 friend modular operator/(modular a, const modular& b) {return a /= b;}
230 };
231
232 typedef modular<int> mi;
233 typedef pair<mi,mi> pmi;
234 typedef vector<mi> vmi;
235 typedef vector<pmi> vpmi;
236
237 mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
238
239 template<class T> using pqg = priority_queue<T,vector<T>,greater<T>>;
240
241 template<class T> T poll(pqg<T>& x)
242 {
243 T y = x.top(); x.pop();
244 return y;
245 }
246
247 int nex;
CAPITOLUL 2. IOI 2019 247
248
249 template<int SZ> struct Dijkstra
250 {
251 ll dist[SZ];
252 vpi adj[SZ];
253
254 void addEdge(int A, int B, int C)
255 {
256 adj[A].pb({B,C}); adj[B].pb({A,C}); assert(C >= 0);
257 // if undirected
258 }
259
260 void init(int st)
261 {
262 fill_n(dist,SZ,INF);
263 pqg<pl> q;
264 q.push({dist[st] = 0,st});
265 while (sz(q))
266 {
267 auto x = poll(q);
268 if (dist[x.s] < x.f) continue;
269 trav(y,adj[x.s])
270 if (x.f+y.s < dist[y.f])
271 q.push({dist[y.f] = x.f+y.s,y.f});
272 }
273 }
274 };
275
276 Dijkstra<10000000> D;
277
278 int N, M, S, G;
279 vi X,H;
280 vector<pair<int,vi>> bridge;
281 vi xx;
282
283 void split(int h, vi& z, set<int>& cur, int x)
284 {
285 vi Z;
286 F0R(i,sz(z)-1)
287 {
288 Z.pb(z[i]);
289 if (z[i] < x && x < z[i+1])
290 {
291 if (H[x] >= h) Z.pb(x);
292 else
293 {
294 auto it = cur.lb(x); assert( *it != x);
295 if (z[i] < *prev(it)) Z.pb( *prev(it));
296 if ( *it < z[i+1]) Z.pb( *it);
297 }
298 }
299 }
300
301 Z.pb(z.back());
302 swap(z,Z);
303 }
304
305 vpi cor[500000];
306 map<int,pi> mm;
307 vector<pair<int,pi>> BRIDGE;
308
309 int makeVert(int seg, int x)
310 {
311 cor[seg].pb({x,nex++});
312 return nex-1;
313 }
314
315 void tri(int seg, int label, int x)
316 {
317 auto it = mm.ub(x); if (it == begin(mm) || prev(it)->s.f < x) return;
318 int SEG = prev(it)->s.s; if (BRIDGE[SEG].f > H[x]) return;
319 int LABEL = makeVert(SEG,x);
320 D.addEdge(label,LABEL,abs(BRIDGE[seg].f-BRIDGE[SEG].f));
321 }
322
323 void ins(int seg)
CAPITOLUL 2. IOI 2019 248
324 {
325 int l = BRIDGE[seg].s.f, r = BRIDGE[seg].s.s;
326 while (1)
327 {
328 auto it = mm.lb(l);
329 if (it != begin(mm) && prev(it)->s.f >= l) it --;
330 if (it == end(mm) || it->f > r) break;
331 auto IT = *it; mm.erase(it);
332 if (IT.f < l) mm[IT.f] = {l-1,IT.s.s};
333 if (IT.s.f > r) mm[r+1] = {IT.s.f,IT.s.s};
334 }
335 mm[l] = {r,seg};
336 }
337
338 ll min_distance(vi x, vi h, vi l, vi r, vi y, int s, int g)
339 {
340 N = sz(x), M = sz(l); if (s > g) swap(s,g);
341 X = x, H = h, S = s, G = g;
342 F0R(i,sz(l)) bridge.pb({y[i],{l[i],r[i]}});
343
344 sort(bridge.rbegin(),bridge.rend());
345
346 F0R(i,N) xx.pb(i);
347
348 sort(all(xx),[](int a, int b) { return H[a] > H[b]; });
349
350 int ind = 0; set<int> cur;
351
352 trav(z,bridge)
353 {
354 while (ind < sz(xx) && H[xx[ind]] >= z.f) cur.insert(xx[ind++]);
355 // ps("??",z.f,cur);
356 split(z.f,z.s,cur,S);
357 split(z.f,z.s,cur,G);
358 }
359
360 trav(z,bridge) F0R(i,sz(z.s)-1) BRIDGE.pb({z.f,{z.s[i],z.s[i+1]}});
361 BRIDGE.pb({0,{S,S}}); BRIDGE.pb({0,{G,G}});
362 vi special;
363 F0R(i,sz(BRIDGE))
364 {
365 cor[i] = {{BRIDGE[i].s.f,2*i},{BRIDGE[i].s.s,2*i+1}};
366 if (BRIDGE[i].f == 0) special.pb(2*i);
367 }
368
369 nex = 2*sz(BRIDGE);
370 F0R(i,sz(BRIDGE))
371 {
372 // ps("HUH",i,BRIDGE[i]);
373 tri(i,2*i,BRIDGE[i].s.f);
374 tri(i,2*i+1,BRIDGE[i].s.s);
375 ins(i);
376 }
377
378 mm.clear();
379 F0Rd(i,sz(BRIDGE))
380 {
381 tri(i,2*i,BRIDGE[i].s.f);
382 tri(i,2*i+1,BRIDGE[i].s.s);
383 ins(i);
384 }
385
386 // add bridge edges
387 F0R(i,sz(BRIDGE))
388 {
389 sort(all(cor[i]));
390 F0R(j,sz(cor[i])-1)
391 D.addEdge(cor[i][j].s,
392 cor[i][j+1].s,
393 X[cor[i][j+1].f]-X[cor[i][j].f]);
394 }
395
396 D.init(special[0]);
397 auto res = D.dist[special[1]];
398 if (res == INF) res = -1;
399 return res;
CAPITOLUL 2. IOI 2019 249
97
98 nxt.resize(unique(nxt.begin(), nxt.end()) - nxt.begin());
99 witness[i] = nxt;
100 }
101 }
102
103 long long min_distance(vector<int> x, vector<int> h,
104 vector<int> l, vector<int> r,
105 vector<int> y, int s, int e)
106 {
107 n = sz(x);
108 m = sz(l);
109 for(int i=0; i<m; i++)
110 {
111 witness[l[i]].push_back(y[i]);
112 witness[r[i]].push_back(y[i]);
113 }
114
115 witness[s].push_back(0);
116 witness[e].push_back(0);
117
118 vector<pi> points;
119 vector<intv> hors;
120
121 set<int> alive;
122 for(int i=0; i<n; i++)
123 {
124 points.emplace_back(h[i], i);
125 alive.insert(i);
126 }
127
128 for(int i=0; i<m; i++) hors.push_back({l[i], r[i], y[i]});
129
130 sort(points.begin(), points.end());
131 sort(hors.begin(), hors.end());
132
133 int ptr = 0;
134 for(auto &i : hors)
135 {
136 while(ptr < sz(points) && points[ptr].first < i.x)
137 {
138 alive.erase(points[ptr++].second);
139 }
140
141 if(i.s <= s && s <= i.e)
142 {
143 auto it = alive.lower_bound(s);
144 witness[ *it ].push_back(i.x);
145 if( *it != s) witness[ *prev(it) ].push_back(i.x);
146 }
147
148 if(i.s <= e && e <= i.e)
149 {
150 auto it = alive.lower_bound(e);
151 witness[ *it ].push_back(i.x);
152 if( *it != e) witness[ *prev(it) ].push_back(i.x);
153 }
154 }
155
156 make_vertex(hors);
157 vector<point> ans;
158 for(int i=0; i<n; i++)
159 {
160 for(auto &j : witness[i])
161 {
162 int num = ans.size();
163 ans.push_back({x[i], j, num});
164 }
165 }
166
167 assert(sz(ans) < MAXV);
168 auto cmpx = [&](const point &x, const point &y)
169 { return pi(x.x, x.y) < pi(y.x, y.y); };
170 auto cmpy = [&](const point &x, const point &y)
171 { return pi(x.y, x.x) < pi(y.y, y.x); };
172
CAPITOLUL 2. IOI 2019 252
IOI 201826
3.1 Combo
Problema 1 - Combo 100 de puncte
Author: Ammar Fathin Sabili (Indonesia)
Detalii de implementare
26
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).
254
CAPITOLUL 3. IOI 2018 255
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 evaluat ca
Wrong answer. Altfel, programul vostru va evaluat ca Accepted, iar punctajul vostru va
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
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 3. IOI 2018 256
Dac programul vostru este evaluat ca Accepted, atunci grader-ul local va a³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 a³a
Wrong answer: M SG. Semnicaµ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 .
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 rst position, determine the character by three asks. For each position except the
rst 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 rst or last position, determine the character by one ask as follows.
` Assume that the rst character of S is, for example, 'A'.
` Let s be the prex 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.
36 }
37 for (int i = 0; i < len; ++i)
38 {
39 if (p[i] != ’A’ && p[i] != ’B’ && p[i] != ’X’ && p[i] != ’Y’)
40 {
41 wrong_answer("invalid press");
42 }
43 }
44 int coins = 0;
45 for (int i = 0, j = 0; i < len; ++i)
46 {
47 if (j < N && S[j] == p[i])
48 {
49 ++j;
50 } else if (S[0] == p[i])
51 {
52 j = 1;
53 }
54 else
55 {
56 j = 0;
57 }
58 coins = std::max(coins, j);
59 }
60 return coins;
61 }
62
63 int main()
64 {
65 char buffer[MAX_N + 1];
66 if (scanf("%s", buffer) != 1)
67 {
68 fprintf(stderr, "Error while reading input\n");
69 exit(1);
70 }
71 S = buffer;
72 N = S.length();
73
74 num_moves = 0;
75 std::string answer = guess_sequence(N);
76 if (answer != S)
77 {
78 wrong_answer("wrong guess");
79 exit(0);
80 }
81 printf("Accepted: %d\n", num_moves);
82 return 0;
83 }
25 int press(std::string p)
26 {
27 if (++num_moves > MAX_NUM_MOVES) { wrong_answer("too many moves"); }
28
29 int len = p.length();
30 if (len > 4 * N) { wrong_answer("invalid press"); }
31
32 for (int i = 0; i < len; ++i)
33 {
34 if (p[i] != ’A’ && p[i] != ’B’ && p[i] != ’X’ && p[i] != ’Y’)
35 {
36 wrong_answer("invalid press");
37 }
38 }
39 int coins = 0;
40 for (int i = 0, j = 0; i < len; ++i)
41 {
42 if (j < N && S[j] == p[i]) { ++j; }
43 else if (S[0] == p[i]) { j = 1; }
44 else { j = 0; }
45 coins = std::max(coins, j);
46 }
47 return coins;
48 }
49
50 string guess_sequence(int N)
51 {
52 string p = "";
53 if(press("AB") >= 1) p = press("A") ? "A" : "B";
54 else p = press("X") ? "X" : "Y";
55
56 vector<char> chr = {’A’, ’B’, ’X’, ’Y’};
57 chr.erase(find(chr.begin(), chr.end(), p[0]));
58
59 while((int)p.size() <= N - 2)
60 {
61 int query = press(p+chr[0]+chr[0]+p+chr[0]+chr[1]+p+chr[1]+chr[0]);
62 if(query == p.size())
63 {
64 p.push_back(chr[2]);
65 }
66 else
67 if(query == p.size() + 1)
68 {
69 query = press(p + chr[1] + chr[2]);
70 if(query == p.size()) p = p + chr[0] + chr[2];
71 else if(query == p.size() + 1) p = p + chr[1] + chr[1];
72 else p = p + chr[1] + chr[2];
73 }
74 else
75 {
76 query = press(p + chr[0] + chr[1]);
77 if(query == p.size()) p = p + chr[1] + chr[0];
78 else if(query == p.size() + 1) p = p + chr[0] + chr[0];
79 else p = p + chr[0] + chr[1];
80 }
81 }
82 while(p.size() != N)
83 {
84 if(press(p + chr[0]) == p.size() + 1) p.push_back(chr[0]);
85 else if(press(p + chr[1]) == p.size() + 1) p.push_back(chr[1]);
86 else p.push_back(chr[2]);
87 }
88 return p;
89 }
90
91 int main()
92 {
93 std::freopen("../in/02-077.txt", "r", stdin);
94 //std::freopen("combo.out", "w", stdout) ;
95
96 char buffer[MAX_N + 1];
97 if (scanf("%s", buffer) != 1)
98 {
99 fprintf(stderr, "Error while reading input\n");
100 exit(1);
CAPITOLUL 3. IOI 2018 260
101 }
102 S = buffer;
103 N = S.length();
104
105 num_moves = 0;
106 std::string answer = guess_sequence(N); // functia de implementat ... !!!
107 if (answer != S)
108 {
109 wrong_answer("wrong guess");
110 exit(0);
111 }
112 printf("Accepted: num_moves=%d N=%d\n", num_moves,N);
113 return 0;
114 }
10
11 namespace
12 {
13 constexpr int MAX_N = 2000;
14 constexpr int MAX_NUM_MOVES = 8000;
15
16 int N;
17 std::string S;
18 int num_moves;
19
20 void wrong_answer(const char *MSG)
21 {
22 printf("Wrong Answer: %s\n", MSG);
23 exit(0);
24 }
25 }
26
27 int press(std::string p)
28 {
29 if (++num_moves > MAX_NUM_MOVES) { wrong_answer("too many moves"); }
30
31 int len = p.length();
32 if (len > 4 * N) { wrong_answer("invalid press"); }
33
34 for (int i = 0; i < len; ++i)
35 {
36 if (p[i] != ’A’ && p[i] != ’B’ && p[i] != ’X’ && p[i] != ’Y’)
37 {
38 wrong_answer("invalid press");
39 }
40 }
41
42 int coins = 0;
43 for (int i = 0, j = 0; i < len; ++i)
44 {
45 if (j < N && S[j] == p[i]) { ++j; }
46 else if (S[0] == p[i]) { j = 1; }
47 else { j = 0; }
48 coins = std::max(coins, j);
49 }
50
51 return coins;
52 }
53
54 const static char b[5] = "ABXY";
55
56 static string r;
57 static char a[3];
58
59 string guess_sequence(int N)
60 {
61 int x = press(string("XY"));
62 int y = press(string("BY"));
63
64 r += b[2 * !!x + !!y];
65 for(int i = 0, j = 0; i < 4; i++) if(i != 2 * !!x + !!y) a[j++] = b[i];
66
67 for(int x; r.length() < N - 1; )
68 {
69 x = press(r + a[0] + a[0] + r + a[0] + a[1] + r + a[1] + a[0]);
70 if(x == r.length()){ r += a[2]; continue; }
71 if(x == r.length() + 1)
72 {
73 x = press(r + a[1] + r + a[1] + a[1]);
74 if(x == r.length()){ r += a[0]; r += a[2]; }
75 if(x == r.length() + 1){ r += a[1]; r += a[2]; }
76 if(x == r.length() + 2){ r += a[1]; r += a[1]; }
77 }
78 else
79 {
80 x = press(r + a[0] + r + a[0] + a[0]);
81 if(x == r.length()){ r += a[1]; r += a[0]; }
82 if(x == r.length() + 1){ r += a[0]; r += a[1]; }
83 if(x == r.length() + 2){ r += a[0]; r += a[0]; }
84 }
85 }
CAPITOLUL 3. IOI 2018 263
86
87 if(r.length() < N)
88 {
89 int x = press(r + "X" + r + "Y");
90 int y = press(r + "B" + r + "Y");
91 r += b[2 * (x - r.length()) + (y - r.length())];
92 }
93
94 return r;
95 }
96
97 int main()
98 {
99 std::freopen("../in/02-077.txt", "r", stdin) ;
100 //std::freopen("combo.out", "w", stdout) ;
101
102 char buffer[MAX_N + 1];
103 if (scanf("%s", buffer) != 1)
104 {
105 fprintf(stderr, "Error while reading input\n");
106 exit(1);
107 }
108 S = buffer;
109 N = S.length();
110
111 num_moves = 0;
112
113 std::string answer = guess_sequence(N);
114
115 if (answer != S)
116 {
117 wrong_answer("wrong guess");
118 exit(0);
119 }
120
121 printf("Accepted: num_moves=%d N=%d\n", num_moves,N);
122 return 0;
123 }
35 {
36 if (p[i] != ’A’ && p[i] != ’B’ && p[i] != ’X’ && p[i] != ’Y’)
37 {
38 wrong_answer("invalid press");
39 }
40 }
41
42 int coins = 0;
43 for (int i = 0, j = 0; i < len; ++i)
44 {
45 if (j < N && S[j] == p[i]) { ++j; }
46 else if (S[0] == p[i]) { j = 1; }
47 else { j = 0; }
48 coins = std::max(coins, j);
49 }
50
51 return coins;
52 }
53
54 std::string guess_sequence(int N)
55 {
56 char first = press("AB") == 0? "YX"[press("X")]:
57 "BA"[press("A")];
58
59 char a, b, c;
60 if(first == ’A’) a = ’B’, b = ’X’, c = ’Y’;
61 if(first == ’B’) a = ’A’, b = ’X’, c = ’Y’;
62 if(first == ’X’) a = ’A’, b = ’B’, c = ’Y’;
63 if(first == ’Y’) a = ’A’, b = ’B’, c = ’X’;
64
65 std::string S(1, first);
66 while(S.length() + 2 <= N)
67 {
68 int coins = press(S + a + a + S + a + b + S + b + a) - S.length();
69 if (coins == 0)
70 {
71 S += c;
72 }
73 else
74 if (coins == 1)
75 {
76 coins = press(S + b + c) - S.length();
77 if (coins == 0)
78 {
79 S += a, S += c;
80 }
81 else
82 if (coins == 1)
83 {
84 S += b, S += b;
85 }
86 else
87 if (coins == 2)
88 {
89 S += b, S += c;
90 }
91 }
92 else
93 if (coins == 2)
94 {
95 coins = press(S + a + b) - S.length();
96 if (coins == 0)
97 {
98 S += b, S += a;
99 }
100 else
101 if (coins == 1)
102 {
103 S += a, S += a;
104 }
105 else
106 if (coins == 2)
107 {
108 S += a, S += b;
109 }
110 }
CAPITOLUL 3. IOI 2018 265
111 }
112
113 if (S.length() < N)
114 {
115 if (press(S + a) - S.length() == 1)
116 {
117 S += a;
118 }
119 else
120 if(press(S + b) - S.length() == 1)
121 {
122 S += b;
123 }
124 else
125 {
126 S += c;
127 }
128 }
129
130 return S;
131 }
132
133 int main()
134 {
135 std::freopen("../in/02-077.txt", "r", stdin) ;
136 //std::freopen("combo.out", "w", stdout) ;
137
138 char buffer[MAX_N + 1];
139 if (scanf("%s", buffer) != 1)
140 {
141 fprintf(stderr, "Error while reading input\n");
142 exit(1);
143 }
144 S = buffer;
145 N = S.length();
146
147 num_moves = 0;
148
149 std::string answer = guess_sequence(N);
150
151 if (answer != S)
152 {
153 wrong_answer("wrong guess");
154 exit(0);
155 }
156
157 printf("Accepted: num_moves=%d N=%d\n", num_moves,N);
158 return 0;
159 }
24 }
25 }
26
27 int press(std::string p)
28 {
29 if (++num_moves > MAX_NUM_MOVES) { wrong_answer("too many moves"); }
30
31 int len = p.length();
32 if (len > 4 * N) { wrong_answer("invalid press"); }
33
34 for (int i = 0; i < len; ++i)
35 {
36 if (p[i] != ’A’ && p[i] != ’B’ && p[i] != ’X’ && p[i] != ’Y’)
37 {
38 wrong_answer("invalid press");
39 }
40 }
41
42 int coins = 0;
43 for (int i = 0, j = 0; i < len; ++i)
44 {
45 if (j < N && S[j] == p[i]) { ++j; }
46 else if (S[0] == p[i]) { j = 1; }
47 else { j = 0; }
48 coins = std::max(coins, j);
49 }
50
51 return coins;
52 }
53
54 std::string guess_sequence(int N)
55 {
56 int sr = 0;
57 if (press("AB") > 0) sr += 2;
58 if (press("AX") > 0) sr++;
59 string sc[4] = {"Y", "X", "B", "A"};
60 string s = "";
61 s += sc[sr];
62 string c[3];
63 int cs = 0;
64 for (int i = 0; i < 4; i++)
65 if (i != sr)
66 {
67 c[cs] = sc[i];
68 cs++;
69 }
70
71 for (int i = 1; i < N; i++)
72 {
73 string ts;
74 if (i == N-1) ts = s + c[1] + s + c[2];
75 else ts = s + c[1] + c[0] + s + c[2] + c[0] + s + c[2] + c[2];
76 int t = press(ts) - s.length();
77 if (t != 0 && i == N-1)
78 {
79 int t1 = press(s + c[1]) - s.length();
80 if (t1 == 0) s += c[2];
81 else s += c[1];
82 continue;
83 }
84
85 if (t == 0) s += c[0];
86 else if (t == 1)
87 {
88 string ps = s + c[1] + c[2];
89 int t1 = press(ps) - s.length();
90 if (t1 == 0) s += c[2] + c[1];
91 else if (t1 == 1) s += c[1] + c[1];
92 else s += c[1] + c[2];
93 i++;
94 }
95 else
96 {
97 string ps = s + c[2] + c[0];
98 int t1 = press(ps) - s.length();
99 if (t1 == 0) s += c[1] + c[0];
CAPITOLUL 3. IOI 2018 267
37 wrong_answer("invalid press");
38 }
39 }
40 int coins = 0;
41 for (int i = 0, j = 0; i < len; ++i)
42 {
43 if (j < N && S[j] == p[i]) { ++j; }
44 else if (S[0] == p[i]) { j = 1; }
45 else { j = 0; }
46 coins = std::max(coins, j);
47 }
48 return coins;
49 }
50
51 std::string guess_sequence(int N)
52 {
53 std::string p = "";
54 if(press("AB") >= 1) p = press("A") ? "A" : "B";
55 else p = press("X") ? "X" : "Y";
56 std::vector<char> chr = {’A’, ’B’, ’X’, ’Y’};
57 chr.erase(find(chr.begin(), chr.end(), p[0]));
58
59 while((int)p.size() <= N - 2)
60 {
61 int query = press(p + chr[0] + chr[0] +
62 p + chr[0] + chr[1] +
63 p + chr[1] + chr[0]);
64 if(query == p.size())
65 {
66 p.push_back(chr[2]);
67 }
68 else
69 if(query == p.size() + 1)
70 {
71 query = press(p + chr[1] + chr[2]);
72 if(query == p.size()) p = p + chr[0] + chr[2];
73 else
74 if(query == p.size() + 1) p = p + chr[1] + chr[1];
75 else p = p + chr[1] + chr[2];
76 }
77 else
78 {
79 query = press(p + chr[0] + chr[1]);
80 if(query == p.size()) p = p + chr[1] + chr[0];
81 else
82 if(query == p.size() + 1) p = p + chr[0] + chr[0];
83 else p = p + chr[0] + chr[1];
84 }
85 }
86
87 while(p.size() != N)
88 {
89 if(press(p + chr[0]) == p.size() + 1) p.push_back(chr[0]);
90 else
91 if(press(p + chr[1]) == p.size() + 1) p.push_back(chr[1]);
92 else p.push_back(chr[2]);
93 }
94
95 return p;
96 }
97
98 int main()
99 {
100 std::freopen("../in/02-077.txt", "r", stdin) ;
101 //std::freopen("combo.out", "w", stdout) ;
102
103 char buffer[MAX_N + 1];
104 if (scanf("%s", buffer) != 1)
105 {
106 fprintf(stderr, "Error while reading input\n");
107 exit(1);
108 }
109 S = buffer;
110 N = S.length();
111
112 num_moves = 0;
CAPITOLUL 3. IOI 2018 269
113
114 std::string answer = guess_sequence(N);
115
116 if (answer != S)
117 {
118 wrong_answer("wrong guess");
119 exit(0);
120 }
121
122 printf("Accepted: num_moves=%d N=%d\n", num_moves,N);
123 return 0;
124 }
3.2 Seats
Problema 2 - Seats 100 de puncte
Author: Mikhail Pyaderkin (Russia)
Detalii de implementare
Exemple
0 3 4
1 2 5
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 dreptun-
ghiulare ³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 eciently using a lazy propagation segment tree and deal with each
query in O log HW time.
CAPITOLUL 3. IOI 2018 272
38 give_initial_chart(H, W, R, C);
39 for (int j = 0; j < Q; ++j)
40 {
41 int answer = swap_seats(A[j], B[j]);
42 printf("%d\n", answer);
43 }
44 return 0;
45 }
65 while (x)
66 {
67 IT[x] = IT[x*2] * IT[x*2+1];
68 x /= 2;
69 }
70 }
71
72 set<int> ups;
73
74 void add(int i, int p, bool up = true)
75 {
76 if (p > 0)
77 {
78 if (chk[i]) return;
79 chk[i] = 1;
80 }
81 else
82 {
83 if (!chk[i]) return;
84 chk[i] = 0;
85 }
86
87 int x = R[i], y = C[i];
88 int dx[5] = {0,1,0,-1,0};
89 int dy[5] = {1,0,-1,0,1};
90
91 for (int k=0;k<4;k++)
92 {
93 int u[2];
94 for (int d=0;d<2;d++)
95 {
96 int px = x + dx[k+d];
97 int py = y + dy[k+d];
98 if (px < 0 || px >= H || py < 0 || py >= W) u[d] = N;
99 else u[d] = A[px*W+py];
100 }
101
102 int s = N, e = 0;
103 if (i < u[0] && i < u[1])
104 {
105 s = i + Z;
106 e = min(u[0],u[1]) + Z;
107 }
108
109 if (u[0] < i && u[1] < i)
110 {
111 s = max(u[0],u[1]) + Z;
112 e = i + Z;
113 }
114
115 if (s < e)
116 {
117 IT[s].add(+p);
118 IT[e].add(-p);
119 if (up)
120 {
121 ups.insert(s);
122 ups.insert(e);
123 }
124 }
125 }
126 }
127
128 void give_initial_chart(int H_, int W_, vector<int> R_, vector<int> C_)
129 {
130 H = H_; W = W_; R = R_; C = C_; N = H * W;
131 for (int i=0;i<N;i++) A[R[i]*W+C[i]] = i;
132 IT[N+Z].add(10000);
133 for (int i=0;i<N;i++) add(i,1,false);
134 for (int i=Z-1;i>=1;i--) IT[i] = IT[i*2] * IT[i*2+1];
135 }
136
137 int swap_seats(int a, int b)
138 {
139 int dx[5] = {0,1,0,-1,0};
140 int dy[5] = {1,0,-1,0,0};
CAPITOLUL 3. IOI 2018 275
217 {
218 int answer = swap_seats(A[j], B[j]);
219 printf("%d\n", answer);
220 }
221
222 auto t4 = clock();
223 fclose(stdout);
224
225 // reset console output
226 freopen("CON", "w", stdout);
227
228 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
229 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
230 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
231
232 return 0;
233 }
234 //======================================================================
235 /*
236 t2-t1 = 0.896
237 t3-t2 = 0.449
238 t4-t3 = 1.873
239
240 Process returned 0 (0x0) execution time : 3.909 s
241 Press any key to continue.
242 */
243 //======================================================================
46 if (s == e)
47 {
48 seg[i].mn = v[s];
49 seg[i].ct = 1;
50 seg[i].lz = 0;
51 return;
52 }
53
54 int m = (s + e) / 2;
55 init(i << 1, s, m, v);
56 init(i << 1 | 1, m + 1, e, v);
57 seg[i] = seg[i << 1] + seg[i << 1 | 1];
58 }
59
60 void spread(int i)
61 {
62 seg[i << 1].mn += seg[i].lz;
63 seg[i << 1].lz += seg[i].lz;
64 seg[i << 1 | 1].mn += seg[i].lz;
65 seg[i << 1 | 1].lz += seg[i].lz;
66 seg[i].lz = 0;
67 }
68
69 void update(int i, int s, int e, int x, int y, llong v)
70 {
71 if (e < x || y < s) return;
72 if (x <= s && e <= y)
73 {
74 seg[i].mn += v;
75 seg[i].lz += v;
76 return;
77 }
78
79 spread(i);
80 int m = (s + e) / 2;
81 update(i << 1, s, m, x, y, v);
82 update(i << 1 | 1, m + 1, e, x, y, v);
83 seg[i] = seg[i << 1] + seg[i << 1 | 1];
84 }
85
86 int get() const
87 {
88 return seg[1].ct;
89 }
90 } seg;
91
92 int getIdx(int x, int y)
93 {
94 if (x < 0 || h <= x || y < 0 || w <= y) return n;
95 return idx[x][y];
96 }
97
98 void update(int x, int y, int v)
99 {
100 int A[4] = { getIdx(x - 1, y - 1), getIdx(x - 1, y)
101 , getIdx(x, y - 1), getIdx(x, y) };
102 sort(A, A + 4);
103 seg.update(1, 0, n - 1, A[0], A[1] - 1, v);
104 seg.update(1, 0, n - 1, A[2], A[3] - 1, v * (1ll << 30));
105 }
106
107 void give_initial_chart(int H, int W, vector<int> R, vector<int> C)
108 {
109 idx.resize(H, vector<int>(W, 0));
110 ::R = R; ::C = C;
111 h = H; w = W; n = H * W;
112 for (int i = 0; i < n; ++i)
113 {
114 idx[R[i]][C[i]] = i;
115 }
116
117 vector<llong> sum(n + 1, 0);
118 for (int i = 0; i <= h; ++i)
119 {
120 for (int j = 0; j <= w; ++j)
121 {
CAPITOLUL 3. IOI 2018 278
41 if(dta)
42 {
43 if(lc)lc->tagdta(dta);
44 if(rc)rc->tagdta(dta);
45 dta=0;
46 }
47 }
48
49 void update()
50 {
51 if(lc->s<rc->s)
52 {
53 s=lc->s;
54 cnt=lc->cnt;
55 }
56 else if(rc->s<lc->s)
57 {
58 s=rc->s;
59 cnt=rc->cnt;
60 }
61 else
62 {
63 s=lc->s;
64 cnt=lc->cnt+rc->cnt;
65 }
66 }
67
68 void Add(int l,int r,const int &a,const int &b,const int &c)
69 {
70 if(l>=a&&r<=b)
71 {
72 tagdta(c);
73 return;
74 }
75 int mid=l+r>>1;
76 downdate();
77 if(a<=mid)lc->Add(l,mid,a,b,c);
78 if(b>mid)rc->Add(mid+1,r,a,b,c);
79 update();
80 }
81
82 } ndl[maxn*2],*ns=ndl,*root;
83
84 node* build(int l,int r)
85 {
86 node *x=ns++;
87 x->dta=0;
88 if(l==r)
89 {
90 x->s=presum[l];
91 x->cnt=1;
92 x->lc=x->rc=NULL;
93 }
94 else
95 {
96 int mid=l+r>>1;
97 x->lc=build(l,mid);
98 x->rc=build(mid+1,r);
99 x->update();
100 }
101 return x;
102 }
103
104 int& seat(int *s,const int &x,const int &y)
105 {
106 if(x>=0&&x<H&&y>=0&&y<W)return s[x*W+y];
107 return NUM;
108 }
109
110 const int ValTable[2][3]={
111 {1,-1,-1},
112 {1,1,-1}
113 };
114
115 int CalcVal(int *s,const int &x,const int &y,const int w=15)
116 {
CAPITOLUL 3. IOI 2018 281
80 else
81 {
82 if (!chk[i]) return;
83 chk[i] = 0;
84 }
85
86 int x = R[i], y = C[i];
87 int dx[5] = {0,1,0,-1,0};
88 int dy[5] = {1,0,-1,0,1};
89
90 for (int k=0;k<4;k++)
91 {
92 int u[2];
93 for (int d=0;d<2;d++)
94 {
95 int px = x + dx[k+d];
96 int py = y + dy[k+d];
97 if (px < 0 || px >= H || py < 0 || py >= W) u[d] = N;
98 else u[d] = A[px*W+py];
99 }
100
101 int s = N, e = 0;
102 if (i < u[0] && i < u[1])
103 {
104 s = i + Z;
105 e = min(u[0],u[1]) + Z;
106 }
107
108 if (u[0] < i && u[1] < i)
109 {
110 s = max(u[0],u[1]) + Z;
111 e = i + Z;
112 }
113
114 if (s < e)
115 {
116 IT[s].add(+p);
117 IT[e].add(-p);
118 if (up)
119 {
120 ups.insert(s);
121 ups.insert(e);
122 }
123 }
124 }
125 }
126
127 void give_initial_chart(int H_, int W_, vector<int> R_, vector<int> C_)
128 {
129 H = H_; W = W_; R = R_; C = C_; N = H * W;
130 for (int i=0;i<N;i++) A[R[i]*W+C[i]] = i;
131 IT[N+Z].add(10000);
132 for (int i=0;i<N;i++) add(i,1,false);
133 for (int i=Z-1;i>=1;i--) IT[i] = IT[i*2] * IT[i*2+1];
134 }
135
136 int swap_seats(int a, int b)
137 {
138 int dx[5] = {0,1,0,-1,0};
139 int dy[5] = {1,0,-1,0,0};
140 for (int i : {a,b}) for (int k=0;k<5;k++)
141 {
142 int x = R[i] + dx[k];
143 int y = C[i] + dy[k];
144 if (x < 0 || x >= H || y < 0 || y >= W) continue;
145 add(A[x*W+y],-1);
146 }
147
148 swap(R[a],R[b]);
149 swap(C[a],C[b]);
150 A[R[a]*W+C[a]] = a;
151 A[R[b]*W+C[b]] = b;
152
153 for (int i : {a,b}) for (int k=0;k<5;k++)
154 {
155 int x = R[i] + dx[k];
CAPITOLUL 3. IOI 2018 285
232 /*
233 t2-t1 = 3.182
234 t3-t2 = 0.458
235 t4-t3 = 4.476
236
237 Process returned 0 (0x0) execution time : 8.239 s
238 Press any key to continue.
239 */
65 }
66
67 pii min(pii a, pii b)
68 {
69 if(a.second<b.second)return a;
70 if(a.second>b.second)return b;
71 if(a.first>b.first)return b;
72 return a;
73 }
74
75 void build(int a, int b, int node)
76 {
77 if(a==b)
78 {
79 sum[node]=arr[a];
80 minimo[node]=arr[a];
81 counter[node]=1;
82 return;
83 }
84
85 int mid=(a+b)/2;
86 build(a,mid,2*node);
87 build(mid+1,b,2*node+1);
88 sum[node]=Sum(sum[2*node],sum[2*node+1]);
89 minimo[node]=min(minimo[2*node],Sum(minimo[2*node+1],sum[2*node]));
90 counter[node]=0;
91 if(minimo[node]==minimo[2*node])
92 {
93 counter[node]+=counter[2*node];
94 }
95
96 if(minimo[node]==Sum(minimo[2*node+1],sum[2*node]))
97 {
98 counter[node]+=counter[2*node+1];
99 }
100 }
101
102 void update(int a, int b, int node, int pos)
103 {
104 if(pos<a || b<pos)return;
105 if(a==b)
106 {
107 sum[node]=arr[a];
108 minimo[node]=arr[a];
109 counter[node]=1;
110 return;
111 }
112
113 int mid=(a+b)/2;
114 update(a,mid,2*node,pos);
115 update(mid+1,b,2*node+1,pos);
116 sum[node]=Sum(sum[2*node],sum[2*node+1]);
117 minimo[node]=min(minimo[2*node],Sum(minimo[2*node+1],sum[2*node]));
118
119 counter[node]=0;
120 if(minimo[node]==minimo[2*node])
121 {
122 counter[node]+=counter[2*node];
123 }
124
125 if(minimo[node]==Sum(minimo[2*node+1],sum[2*node]))
126 {
127 counter[node]+=counter[2*node+1];
128 }
129 }
130
131 void give_initial_chart(int H, int W, std::vector<int> R,
132 std::vector<int> C)
133 {
134 h=H;
135 w=W;
136 for(int i=0;i<h;i++)
137 {
138 vector<int> a;
139 for(int j=0;j<w;j++)a.push_back(-1);
140 table.push_back(a);
CAPITOLUL 3. IOI 2018 288
141 }
142
143 for(int i=0;i<w*h;i++)
144 {
145 r[i]=R[i];
146 c[i]=C[i];
147 table[R[i]][C[i]]=i;
148 }
149
150 for(int i=0;i<h;i++)
151 {
152 for(int j=0;j<w;j++)update_pos(i,j);
153 }
154
155 build(0,w*h-1,1);
156 //for(int i=0;i<h*w;i++)cout<<arr[i].second<<endl;
157 //cout<<counter[1]<<endl;
158 }
159
160 int swap_seats(int a, int b)
161 {
162 swap(table[r[a]][c[a]],table[r[b]][c[b]]);
163 swap(r[a],r[b]);
164 swap(c[a],c[b]);
165 for(int i=-1;i<2;i++)
166 {
167 for(int j=-1;j<2;j++)
168 {
169 update_pos(r[a]+i,c[a]+j);
170 if(r[a]+i>=0 && r[a]+i<=h-1 && c[a]+j>=0 && c[a]+j<=w-1)
171 update(0,h*w-1,1,table[r[a]+i][c[a]+j]);
172
173 update_pos(r[b]+i,c[b]+j);
174 if(r[b]+i>=0 && r[b]+i<=h-1 && c[b]+j>=0 && c[b]+j<=w-1)
175 update(0,h*w-1,1,table[r[b]+i][c[b]+j]);
176 }
177 }
178
179 return counter[1];
180 }
181
182 // ----------------------------------------------
183
184 namespace
185 {
186 int read_int()
187 {
188 int x;
189 if (scanf("%d", &x) != 1)
190 {
191 fprintf(stderr, "Error while reading input\n");
192 exit(1);
193 }
194 return x;
195 }
196 }
197
198 int main()
199 {
200 auto t1 = clock();
201
202 std::freopen("../in/06-04.txt", "r", stdin) ;
203 std::freopen("seats.out", "w", stdout) ;
204
205 int H = read_int();
206 int W = read_int();
207 int Q = read_int();
208
209 std::vector<int> R(H * W), C(H * W);
210 for (int i = 0; i < H * W; ++i)
211 {
212 R[i] = read_int();
213 C[i] = read_int();
214 }
215 std::vector<int> A(Q), B(Q);
216
CAPITOLUL 3. IOI 2018 289
187 {
188 int answer = swap_seats(A[j], B[j]);
189 printf("%d\n", answer);
190 }
191
192 auto t4 = clock();
193 fclose(stdout);
194
195 // reset console output
196 freopen("CON", "w", stdout);
197
198 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
199 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
200 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
201
202 return 0;
203 }
204 /*
205 t2-t1 = 0.875
206 t3-t2 = 2.781
207 t4-t3 = 3.508
208
209 Process returned 0 (0x0) execution time : 7.227 s
210 Press any key to continue.
211 */
3.3 Werewolf
Problema 3 - Werewolf 100 de puncte
Authors: Mohammad Roghani (Iran), Helia Ziaei (Iran)
Î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 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.
Planicaµ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
ec rei c l torii aveµi forma unui om. La sfâr³itul ec 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 ecare 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 de orice
lungime.
Detalii de implementare
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
You start the travel in human form, transform yourself from human form to wolf form at
the vertex Vq , and nish 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 3. IOI 2018 295
located. This range can be eciently 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 corres-
ponds 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 .
16 }
17 return x;
18 }
19
20 } // namespace
21
22 int main()
23 {
24 int N = read_int();
25 int M = read_int();
26 int Q = read_int();
27 std::vector<int> X(M), Y(M), S(Q), E(Q), L(Q), R(Q);
28
29 for (int j = 0; j < M; ++j)
30 {
31 X[j] = read_int();
32 Y[j] = read_int();
33 }
34 for (int i = 0; i < Q; ++i)
35 {
36 S[i] = read_int();
37 E[i] = read_int();
38 L[i] = read_int();
39 R[i] = read_int();
40 }
41
42 std::vector<int> A = check_validity(N, X, Y, S, E, L, R);
43 for (size_t i = 0; i < A.size(); ++i)
44 {
45 printf("%d\n", A[i]);
46 }
47 return 0;
48 }
40 adj2[p[i]].push_back(j);
41 }
42 for(array<int, 2> c : b[p[i]])
43 anc[c[1]]=find(c[0]);
44 b[p[i]].clear();
45 d[p[i]]=1;
46 }
47 dfs(p[n-1], st, en);
48 }
49
50 int qry(int i)
51 {
52 int r=0;
53 for(; i; i-=i&-i)
54 r+=ft[i];
55 return r;
56 }
57
58 vector<int> check_validity(int n2, vector<int> x, vector<int> y,
59 vector<int> s, vector<int> e,
60 vector<int> l, vector<int> r)
61 {
62 n=n2;
63 for(int i=0; i<x.size(); ++i)
64 {
65 adj1[x[i]].push_back(y[i]);
66 adj1[y[i]].push_back(x[i]);
67 }
68 q=s.size();
69 for(int i=0; i<n; ++i)
70 p[i]=n-1-i;
71 for(int i=0; i<q; ++i)
72 b[l[i]].push_back({s[i], i});
73 a(st[0], en[0], anc[0]);
74 for(int i=0; i<n; ++i)
75 {
76 adj2[i].clear();
77 p[i]=i;
78 }
79 memset(d, 0, n);
80 dt=0;
81 for(int i=0; i<q; ++i)
82 b[r[i]].push_back({e[i], i});
83 a(st[1], en[1], anc[1]);
84 for(int i=0; i<n; ++i)
85 ta[st[0][i]]=st[1][i];
86 for(int i=0; i<q; ++i)
87 {
88 b[st[0][anc[0][i]]].push_back({i, -1});
89 b[en[0][anc[0][i]]].push_back({i, 1});
90 }
91 vector<int> ans=vector<int>(q);
92 for(int i=0; i<n; ++i)
93 {
94 for(int j=ta[i]+1; j<=n; j+=j&-j)
95 ++ft[j];
96 for(array<int, 2> c : b[i+1])
97 ans[c[0]]+=c[1]*
98 (qry(en[1][anc[1][c[0]]])-qry(st[1][anc[1][c[0]]]));
99 }
100 for(int i=0; i<q; ++i)
101 ans[i]=ans[i]>0;
102 return ans;
103 }
104 //======================================================================
105 namespace
106 {
107 int read_int()
108 {
109 int x;
110 if (scanf("%d", &x) != 1)
111 {
112 fprintf(stderr, "Error while reading input\n");
113 exit(1);
114 }
115 return x;
CAPITOLUL 3. IOI 2018 298
116 }
117 } // namespace
118
119 int main()
120 {
121 auto t1 = clock();
122
123 std::freopen("../in/04-20.txt", "r", stdin) ;
124 std::freopen("werewolf.out", "w", stdout) ;
125
126 int N = read_int();
127 int M = read_int();
128 int Q = read_int();
129 std::vector<int> X(M), Y(M), S(Q), E(Q), L(Q), R(Q);
130
131 for (int j = 0; j < M; ++j)
132 {
133 X[j] = read_int();
134 Y[j] = read_int();
135 }
136 for (int i = 0; i < Q; ++i)
137 {
138 S[i] = read_int();
139 E[i] = read_int();
140 L[i] = read_int();
141 R[i] = read_int();
142 }
143
144 auto t2 = clock();
145
146 std::vector<int> A = check_validity(N, X, Y, S, E, L, R);
147
148 auto t3 = clock();
149
150 for (size_t i = 0; i < A.size(); ++i)
151 {
152 printf("%d\n", A[i]);
153 }
154
155 auto t4 = clock();
156
157 fclose(stdout);
158
159 // reset console output
160 freopen("CON", "w", stdout);
161
162 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
163 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
164 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
165
166 return 0;
167 }
168 //======================================================================
169 /*
170 t2-t1 = 2.685
171 t3-t2 = 1.384
172 t4-t3 = 0.071
173
174 Process returned 0 (0x0) execution time : 4.888 s
175 Press any key to continue.
176 */
177 //======================================================================
11 vector<int> edge[200000];
12
13 struct UF
14 {
15 int par[200000];
16 UF()
17 {
18 for (int i = 0; i < 200000; ++i) par[i] = i;
19 }
20 int find(int x)
21 {
22 if (par[x] != x) return par[x] = find(par[x]);
23 return x;
24 }
25 } Luf, Ruf;
26
27 int Lpar[200000][20];
28 int Rpar[200000][20];
29 vector<int> Lchild[200000];
30 vector<int> Rchild[200000];
31
32 int Lst[200000];
33 int Led[200000];
34 int Rst[200000];
35 int Red[200000];
36 int LRd[200000];
37
38 void dfs(vector<int> child[], int st[], int ed[], int x, int &d)
39 {
40 st[x] = ++d;
41 for (int i : child[x])
42 {
43 dfs(child, st, ed, i, d);
44 }
45 ed[x] = d;
46 }
47
48 struct query
49 {
50 int i, t, x;
51 query(int i, int t, int x) : i(i), t(t), x(x) {}
52 bool operator<(const query &p) const
53 {
54 return t < p.t;
55 }
56 };
57
58 int seg[200001];
59 void update(int i)
60 {
61 while (i <= n)
62 {
63 ++seg[i];
64 i += i & -i;
65 }
66 }
67
68 int sum(int i)
69 {
70 int ret = 0;
71 while (i)
72 {
73 ret += seg[i];
74 i -= i & -i;
75 }
76 return ret;
77 }
78
79 vector<int> check_validity(int N, vector<int> U, vector<int> V,
80 vector<int> X, vector<int> Y,
81 vector<int> L, vector<int> R)
82 {
83 n = N;
84 m = U.size();
85 q = X.size();
86 for (int i = 0; i < m; ++i)
CAPITOLUL 3. IOI 2018 300
87 {
88 edge[U[i]].push_back(V[i]);
89 edge[V[i]].push_back(U[i]);
90 }
91 for (int i = 0; i < n; ++i) Lpar[i][0] = 0;
92 for (int i = n; i--; )
93 {
94 for (int j : edge[i])
95 {
96 if (j < i) continue;
97 int x = Luf.find(i);
98 int y = Luf.find(j);
99 if (x == y) continue;
100 Luf.par[y] = x;
101 Lpar[y][0] = x;
102 Lchild[x].push_back(y);
103 }
104 }
105
106 for (int i = 0; i < n; ++i) Rpar[i][0] = n - 1;
107 for (int i = 0; i < n; ++i)
108 {
109 for (int j : edge[i])
110 {
111 if (i < j) continue;
112 int x = Ruf.find(i);
113 int y = Ruf.find(j);
114 if (x == y) continue;
115 Ruf.par[y] = x;
116 Rpar[y][0] = x;
117 Rchild[x].push_back(y);
118 }
119 }
120
121 for (int i = 1; i < 20; ++i)
122 {
123 for (int j = 0; j < n; ++j)
124 {
125 Lpar[j][i] = Lpar[Lpar[j][i - 1]][i - 1];
126 Rpar[j][i] = Rpar[Rpar[j][i - 1]][i - 1];
127 }
128 }
129
130 int ord;
131 ord = 0;
132 dfs(Lchild, Lst, Led, Luf.find(0), ord);
133 ord = 0;
134 dfs(Rchild, Rst, Red, Ruf.find(0), ord);
135 for (int i = 0; i < n; ++i) LRd[Lst[i] - 1] = Rst[i];
136
137 vector<query> qs;
138 for (int it = 0; it < q; ++it)
139 {
140 int x = X[it];
141 int y = Y[it];
142 int l = L[it];
143 int r = R[it];
144 for (int i = 20; i--; ) if (l <= Lpar[x][i]) x = Lpar[x][i];
145 for (int i = 20; i--; ) if (Rpar[y][i] <= r) y = Rpar[y][i];
146 qs.emplace_back(~it, Lst[x] - 1, y);
147 qs.emplace_back(it, Led[x], y);
148 }
149
150 sort(qs.begin(), qs.end());
151 vector<int> ret(q, 0);
152 ord = 0;
153 for (query i : qs)
154 {
155 while (ord < i.t) update(LRd[ord++]);
156 int v = sum(Red[i.x]) - sum(Rst[i.x] - 1);
157 if (i.i < 0) ret[~i.i] -= v;
158 else ret[i.i] += v;
159 }
160
161 for (int &i : ret) i = (i > 0);
162 return ret;
CAPITOLUL 3. IOI 2018 301
163 }
164
165 //-------------- start grader ------------------
166
167 namespace
168 {
169 int read_int()
170 {
171 int x;
172 if (scanf("%d", &x) != 1)
173 {
174 fprintf(stderr, "Error while reading input\n");
175 exit(1);
176 }
177 return x;
178 }
179 } // namespace
180
181 int main()
182 {
183 auto t1 = clock();
184
185 std::freopen("../in/04-19.txt", "r", stdin);
186 std::freopen("werewolf.out", "w", stdout);
187
188 int N = read_int();
189 int M = read_int();
190 int Q = read_int();
191
192 std::vector<int> X(M), Y(M), S(Q), E(Q), L(Q), R(Q);
193
194 for (int j = 0; j < M; ++j)
195 {
196 X[j] = read_int();
197 Y[j] = read_int();
198 }
199
200 for (int i = 0; i < Q; ++i)
201 {
202 S[i] = read_int();
203 E[i] = read_int();
204 L[i] = read_int();
205 R[i] = read_int();
206 }
207
208 fclose(stdin);
209 auto t2 = clock();
210
211 std::vector<int> A = check_validity(N, X, Y, S, E, L, R);
212
213 auto t3 = clock();
214
215 for (size_t i = 0; i < A.size(); ++i)
216 {
217 printf("%d\n", A[i]);
218 }
219
220 auto t4 = clock();
221
222 // reset console output
223 freopen("CON", "w", stdout);
224
225 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
226 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
227 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
228
229 return 0;
230 }
231 /*
232 t2-t1 = 0.765
233 t3-t2 = 2.094
234 t4-t3 = 0.063
235
236 Process returned 0 (0x0) execution time : 3.109 s
237 Press any key to continue.
238 */
CAPITOLUL 3. IOI 2018 302
227 {
228 auto t1 = clock();
229
230 std::freopen("../in/04-19.txt", "r", stdin);
231 std::freopen("werewolf.out", "w", stdout);
232
233 int N = read_int();
234 int M = read_int();
235 int Q = read_int();
236
237 std::vector<int> X(M), Y(M), S(Q), E(Q), L(Q), R(Q);
238
239 for (int j = 0; j < M; ++j)
240 {
241 X[j] = read_int();
242 Y[j] = read_int();
243 }
244
245 for (int i = 0; i < Q; ++i)
246 {
247 S[i] = read_int();
248 E[i] = read_int();
249 L[i] = read_int();
250 R[i] = read_int();
251 }
252
253 fclose(stdin);
254 auto t2 = clock();
255
256 std::vector<int> A = check_validity(N, X, Y, S, E, L, R);
257
258 auto t3 = clock();
259
260 for (size_t i = 0; i < A.size(); ++i)
261 {
262 printf("%d\n", A[i]);
263 }
264
265 auto t4 = clock();
266
267 // reset console output
268 freopen("CON", "w", stdout);
269
270 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
271 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
272 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
273
274 return 0;
275 }
276 /*
277 t2-t1 = 0.797
278 t3-t2 = 2.411
279 t4-t3 = 0.063
280
281 Process returned 0 (0x0) execution time : 3.427 s
282 Press any key to continue.
283 */
16 {
17 return x==r[x]?x:(r[x]=find(r[x]));
18 }
19
20 void dfs(int u, int st[mxN], int en[mxN])
21 {
22 st[u]=dt++;
23 for(int v : adj2[u])
24 dfs(v, st, en);
25 en[u]=dt;
26 }
27
28 void a(int st[mxN], int en[mxN], int anc[mxN])
29 {
30 for(int i=0; i<n; ++i)
31 r[i]=i;
32 for(int i=0; i<n; ++i)
33 {
34 for(int j : adj1[p[i]])
35 {
36 if(!d[j]||(j=find(j))==p[i])
37 continue;
38 r[j]=p[i];
39 adj2[p[i]].push_back(j);
40 }
41 for(array<int, 2> c : b[p[i]])
42 anc[c[1]]=find(c[0]);
43 b[p[i]].clear();
44 d[p[i]]=1;
45 }
46 dfs(p[n-1], st, en);
47 }
48
49 int qry(int i)
50 {
51 int r=0;
52 for(; i; i-=i&-i)
53 r+=ft[i];
54 return r;
55 }
56
57 vector<int> check_validity(int n2, vector<int> x, vector<int> y,
58 vector<int> s, vector<int> e,
59 vector<int> l, vector<int> r)
60 {
61 n=n2;
62 for(int i=0; i<x.size(); ++i)
63 {
64 adj1[x[i]].push_back(y[i]);
65 adj1[y[i]].push_back(x[i]);
66 }
67
68 q=s.size();
69 for(int i=0; i<n; ++i)
70 p[i]=n-1-i;
71 for(int i=0; i<q; ++i)
72 b[l[i]].push_back({s[i], i});
73
74 a(st[0], en[0], anc[0]);
75 for(int i=0; i<n; ++i)
76 {
77 adj2[i].clear();
78 p[i]=i;
79 }
80
81 memset(d, 0, n);
82
83 dt=0;
84 for(int i=0; i<q; ++i)
85 b[r[i]].push_back({e[i], i});
86
87 a(st[1], en[1], anc[1]);
88 for(int i=0; i<n; ++i)
89 ta[st[0][i]]=st[1][i];
90
91 for(int i=0; i<q; ++i)
CAPITOLUL 3. IOI 2018 307
92 {
93 b[st[0][anc[0][i]]].push_back({i, -1});
94 b[en[0][anc[0][i]]].push_back({i, 1});
95 }
96
97 vector<int> ans=vector<int>(q);
98 for(int i=0; i<n; ++i)
99 {
100 for(int j=ta[i]+1; j<=n; j+=j&-j)
101 ++ft[j];
102 for(array<int, 2> c : b[i+1])
103 ans[c[0]]+=c[1]*
104 (qry(en[1][anc[1][c[0]]])-qry(st[1][anc[1][c[0]]]));
105 }
106
107 for(int i=0; i<q; ++i)
108 ans[i]=ans[i]>0;
109
110 return ans;
111 }
112 //-------------- start grader ------------------
113
114 namespace
115 {
116 int read_int()
117 {
118 int x;
119 if (scanf("%d", &x) != 1)
120 {
121 fprintf(stderr, "Error while reading input\n");
122 exit(1);
123 }
124 return x;
125 }
126 } // namespace
127
128 int main()
129 {
130 auto t1 = clock();
131
132 std::freopen("../in/04-19.txt", "r", stdin);
133 std::freopen("werewolf.out", "w", stdout);
134
135 int N = read_int();
136 int M = read_int();
137 int Q = read_int();
138
139 std::vector<int> X(M), Y(M), S(Q), E(Q), L(Q), R(Q);
140
141 for (int j = 0; j < M; ++j)
142 {
143 X[j] = read_int();
144 Y[j] = read_int();
145 }
146
147 for (int i = 0; i < Q; ++i)
148 {
149 S[i] = read_int();
150 E[i] = read_int();
151 L[i] = read_int();
152 R[i] = read_int();
153 }
154
155 fclose(stdin);
156 auto t2 = clock();
157
158 std::vector<int> A = check_validity(N, X, Y, S, E, L, R);
159
160 auto t3 = clock();
161
162 for (size_t i = 0; i < A.size(); ++i)
163 {
164 printf("%d\n", A[i]);
165 }
166
167 auto t4 = clock();
CAPITOLUL 3. IOI 2018 308
168
169 // reset console output
170 freopen("CON", "w", stdout);
171
172 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
173 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
174 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
175
176 return 0;
177 }
178 /*
179 t2-t1 = 0.781
180 t3-t2 = 1.344
181 t4-t3 = 0.062
182
183 Process returned 0 (0x0) execution time : 2.359 s
184 Press any key to continue.
185 */
55
56 pii get_seg_l(int x, int r)
57 {
58 for(int i=17;i>=0;i--)
59 {
60 if(up[x][i] && up[x][i] <= r) x = up[x][i];
61 }
62 return pii(lv[x], rv[x]);
63 }
64 } T[2];
65
66 int pp[200020];
67 int Find(int x)
68 {
69 return pp[x] == x ? x : pp[x] = Find(pp[x]);
70 }
71
72 int val[200020];
73 vector <int> EE[200010];
74 int N;
75
76 vector <t3> pquery[200020];
77 int TT[200020];
78 int cnt[200020];
79
80 void pre_query(int idx, int S, int E, int L, int R)
81 {
82 pii p1 = T[0].get_seg_l(E, R);
83 pii p2 = T[1].get_seg_g(S, L);
84 pquery[p1.Se].pb(t3(p2.Se, idx, 1));
85 pquery[p1.Se].pb(t3(p2.Fi-1, idx, -1));
86 pquery[p1.Fi-1].pb(t3(p2.Se, idx, -1));
87 pquery[p1.Fi-1].pb(t3(p2.Fi-1, idx, 1));
88 }
89
90 std::vector<int> check_validity(int nn, std::vector<int> X,
91 std::vector<int> Y,
92 std::vector<int> S, std::vector<int> E,
93 std::vector<int> L, std::vector<int> R)
94 {
95 N = nn;
96 int M = szz(X);
97 for(int i=0;i<M;i++)
98 {
99 int x = X[i] + 1, y = Y[i] + 1;
100 EE[x].pb(y);
101 EE[y].pb(x);
102 }
103
104 for(int i=1;i<=N;i++) pp[i] = i;
105 for(int i=1;i<=N;i++) {
106 for(int e : EE[i]) if(e < i)
107 {
108 int x = Find(i), y = Find(e);
109 if(x == y) continue;
110 pp[y] = x;
111 T[0].addE(x, y);
112 }
113 }
114
115 for(int i=1;i<=N;i++) pp[i] = i;
116 for(int i=N;i;i--)
117 {
118 for(int e : EE[i]) if(e > i)
119 {
120 int x = Find(i), y = Find(e);
121 if(x == y) continue;
122 pp[y] = x;
123 T[1].addE(x, y);
124 }
125 }
126
127 T[0].dfs(N); T[1].dfs(1);
128 for(int i=1;i<=N;i++)
129 {
130 val[T[0].lv[i]] = T[1].lv[i];
CAPITOLUL 3. IOI 2018 310
131 }
132
133 int Q = szz(S);
134 rep(i, Q)
135 {
136 ++S[i]; ++E[i]; ++L[i]; ++R[i];
137 pre_query(i, S[i], E[i], L[i], R[i]);
138 }
139
140 for(int i=1;i<=N;i++)
141 {
142 int x = val[i];
143 for(int j=x;j<200020;j+=(j&-j)) TT[j]++;
144 for(t3 e : pquery[i])
145 {
146 int y, idx, cc;
147 tie(y, idx, cc) = e;
148 int s = 0;
149 for(int j=y;j;j-=(j&-j)) s += TT[j];
150 cnt[idx] += cc * s;
151 }
152 }
153
154 vector <int> A(Q);
155 rep(i, Q)
156 {
157 A[i] = cnt[i] > 0 ? 1 : 0;
158 }
159
160 return A;
161 }
162
163 //-------------- start grader ------------------
164
165 namespace
166 {
167 int read_int()
168 {
169 int x;
170 if (scanf("%d", &x) != 1)
171 {
172 fprintf(stderr, "Error while reading input\n");
173 exit(1);
174 }
175 return x;
176 }
177 } // namespace
178
179 int main()
180 {
181 auto t1 = clock();
182
183 std::freopen("../in/04-19.txt", "r", stdin);
184 std::freopen("werewolf.out", "w", stdout);
185
186 int N = read_int();
187 int M = read_int();
188 int Q = read_int();
189
190 std::vector<int> X(M), Y(M), S(Q), E(Q), L(Q), R(Q);
191
192 for (int j = 0; j < M; ++j)
193 {
194 X[j] = read_int();
195 Y[j] = read_int();
196 }
197
198 for (int i = 0; i < Q; ++i)
199 {
200 S[i] = read_int();
201 E[i] = read_int();
202 L[i] = read_int();
203 R[i] = read_int();
204 }
205
206 fclose(stdin);
CAPITOLUL 3. IOI 2018 311
43 vector<int> edge1[2][MAXN];
44
45 struct dsu
46 {
47 int dsu[MAXN];
48 bool flag;
49
50 int get(int u)
51 {
52 return ((u == dsu[u]) ? u : dsu[u] = get(dsu[u]));
53 }
54
55 void merge(int u, int v)
56 {
57 u = get(u);
58 v = get(v);
59 if (flag)
60 {
61 if (u > v) swap(u, v);
62 }
63 else
64 {
65 if (u < v) swap(u, v);
66 }
67 dsu[u] = v;
68 // cerr << u << " => " << v << endl;
69 return;
70 }
71 };
72
73 void dfs(bool flag, int u)
74 {
75 st[flag][u] = T;
76 ft[flag][u] = T;
77 ord[flag][T] = u;
78 T++;
79 for (int v : edge1[flag][u])
80 {
81 if (v == parent[flag][u]) continue;
82 dfs(flag, v);
83 ft[flag][u] = ft[flag][v];
84 }
85 }
86
87 int fen[MAXN];
88
89 void update(int idx, int v)
90 {
91 for (int e = idx + 1; e <= N; e += e & (-e))
92 {
93 fen[e] += v;
94 }
95 return;
96 }
97
98 int query(int idx)
99 {
100 int res = 0;
101 for (int e = idx + 1; e > 0; e -= e & (-e))
102 {
103 res += fen[e];
104 }
105 return res;
106 }
107
108 vector<ppp> queries[MAXN];
109 dsu d[2];
110
111 vi check_validity(int n, vi X, vi Y, vi s, vi e, vi l, vi r)
112 {
113 N = n;
114 d[0].flag = true;
115 for (int i = 0; i < N; i++)
116 {
117 d[0].dsu[i] = i;
118 d[1].dsu[i] = i;
CAPITOLUL 3. IOI 2018 313
119 parent[0][i] = N;
120 parent[1][i] = N;
121 }
122
123 for (int i = 0; i < SZ(X); i++)
124 {
125 int u = X[i], v = Y[i];
126 edge[u].PB(v);
127 edge[v].PB(u);
128 }
129
130 Q = SZ(s);
131 ans.resize(Q);
132 for (int i = 0; i < Q; i++)
133 {
134 swap(s[i], e[i]);
135 quer[i] = MP(MP(l[i], r[i]), MP(s[i], e[i]));
136 }
137
138 for (int i = 0; i < N; i++)
139 {
140 for (int u : edge[i])
141 {
142 if (u > i) continue;
143 u = d[0].get(u);
144 if (u == i) continue;
145 parent[0][u] = i;
146 d[0].merge(u, i);
147 }
148 }
149
150 for (int i = N - 1; i >= 0; i--)
151 {
152 for (int u : edge[i])
153 {
154 if (u < i) continue;
155 u = d[1].get(u);
156 if (u == i) continue;
157 parent[1][u] = i;
158 d[1].merge(u, i);
159 }
160 }
161
162 for (int flag = 0; flag < 2; flag++)
163 {
164 // cerr << "tree\n";
165 for (int i = 0; i < N; i++)
166 {
167 if (parent[flag][i] != N)
168 {
169 edge1[flag][i].PB(parent[flag][i]);
170 edge1[flag][parent[flag][i]].PB(i);
171 // cerr << i << ’ ’ << parent[flag][i] << endl;
172 }
173 }
174 for (int i = 0; i < N; i++)
175 {
176 if (parent[flag][i] == N)
177 {
178 dfs(flag, i);
179 }
180 }
181 T = 0;
182 for (int i = 0; i <= 19; i++)
183 {
184 ancestor[flag][i][N] = N;
185 }
186 for (int i = 0; i < N; i++)
187 {
188 ancestor[flag][0][i] = parent[flag][i];
189 }
190 for (int i = 1; i <= 19; i++)
191 {
192 for (int j = 0; j < N; j++)
193 {
194 ancestor[flag][i][j] =
CAPITOLUL 3. IOI 2018 314
347 return 0;
348 }
349 /*
350 t2-t1 = 0.843
351 t3-t2 = 2.047
352 t4-t3 = 0.063
353
354 Process returned 0 (0x0) execution time : 3.266 s
355 Press any key to continue.
356 */
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
arbitrar (posibil zero) de intr ri. Fiecare tub conecteaz ie³irea unui dispozitiv cu intrarea acelu-
ia³i sau altui dispozitiv. Exact un tub este conectat cu ecare intrare ³i exact un tub este conectat
cu ecare 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 ecare 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 zero). Voi trebuie s decideµi valoarea lui S . Fiecare
dispozitiv are un cod unic de înregistrare.
Originea este dispozitivul unde bila se a iniµial. Are exact o ie³ire. Codul ei unic de înregis-
trare este 0.
Un întrerup tor face bila s execute o mi³care special de ecare 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 e X ,
¬ ¬ ¬ ¬ ¬ ¬
¬ ¬
e Y . Dup ce bila intr într-un comutator îl p r se³te prin ie³irea dat de starea curent a
CAPITOLUL 3. IOI 2018 317
¬ ¬
acestuia. Dup aceea, starea comutatorului se schimb . Iniµial starea ec rui comutator este X .
Codurile unice de înregistrare ale comutatoarelor sunt de la 1 la S .
Detalii de implementare
¬ ¬
conectat cu dispozitivul X j 1 ³i ie³irea Y cu dispozitivul Y j 1.
¬ ¬ ¬ ¬ ¬ ¬
a Orice element a lui C , X ³i Y trebuie s e un num r întreg între S ³i M inclusiv.
a S trebuie s e cel mult 400000.
a Aceast procedur trebuie apelat exact o dat .
¬ ¬ ¬ ¬ ¬ ¬
a Circuitul reprezentat de C , X ³i Y trebuie s satisfac condiµiile din enunµul problemei.
Dac vreuna din condiµiile de mai sus nu este satisf cut programul vostru va evaluat ca
Wrong answer. Altfel, programul vostru va evaluat ca Accepted, iar punctajul vostru va
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
Pentru ecare 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 ecare test din subtask-urile 5 ³i 6, dac N log2 N $ S & 2N veµi primi un punctaj
2
parµial. Punctajul pentru acest test este 0.5 0.4 N2N S
log2 N
multiplicat cu punctajul asociat
subtask-ului.
a Altfel punctajul este 0.
Luaµi la cuno³tinµ c punctajul pentru ecare subtask este minimul punctajelor pentru ecare
test din acel subtask.
Exemplu de grader
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.
44 {
45 if (!(-S <= IC[i] && IC[i] <= M))
46 {
47 wrong_answer("wrong serial number");
48 }
49 }
50 for (int j = 1; j <= S; ++j)
51 {
52 if (!(-S <= IX[j - 1] && IX[j - 1] <= M))
53 {
54 wrong_answer("wrong serial number");
55 }
56 if (!(-S <= IY[j - 1] && IY[j - 1] <= M))
57 {
58 wrong_answer("wrong serial number");
59 }
60 }
61
62 int P = 0;
63 std::vector<bool> state(S + 1, false);
64 int pos = IC[0];
65 int k = 0;
66 FILE *file_log = fopen("log.txt", "w");
67 fprintf(file_log, "0\n");
68 for (;;)
69 {
70 fprintf(file_log, "%d\n", pos);
71 if (pos < 0)
72 {
73 if (++P > P_MAX)
74 {
75 fclose(file_log);
76 char str[50];
77 sprintf(str, "over %d inversions", P_MAX);
78 wrong_answer(str);
79 }
80 state[-pos] = !state[-pos];
81 pos = state[-pos] ? IX[-(1 + pos)] : IY[-(1 + pos)];
82 }
83 else
84 {
85 if (pos == 0)
86 {
87 break;
88 }
89 if (k >= N)
90 {
91 fclose(file_log);
92 wrong_answer("wrong motion");
93 }
94 if (pos != A[k++])
95 {
96 fclose(file_log);
97 wrong_answer("wrong motion");
98 }
99 pos = IC[pos];
100 }
101 }
102 fclose(file_log);
103 if (k != N)
104 {
105 wrong_answer("wrong motion");
106 }
107 for (int j = 1; j <= S; ++j)
108 {
109 if (state[j])
110 {
111 wrong_answer("state ’Y’");
112 }
113 }
114 printf("Accepted: %d %d\n", S, P);
115 }
116
117 } // namespace
118
119 void answer(std::vector<int> C, std::vector<int> X, std::vector<int> Y)
CAPITOLUL 3. IOI 2018 323
120 {
121 if (answered)
122 {
123 wrong_answer("answered not exactly once");
124 }
125 answered = true;
126 // check if input format is correct
127 if ((int)C.size() != M + 1)
128 {
129 wrong_answer("wrong array length");
130 }
131 if (X.size() != Y.size())
132 {
133 wrong_answer("wrong array length");
134 }
135 S = X.size();
136 IC = C;
137 IX = X;
138 IY = Y;
139 }
140
141 int main()
142 {
143 M = read_int();
144 N = read_int();
145 A.resize(N);
146 for (int k = 0; k < N; ++k)
147 {
148 A[k] = read_int();
149 }
150
151 answered = false;
152 create_circuit(M, A);
153 if (!answered)
154 {
155 wrong_answer("answered not exactly once");
156 }
157 FILE *file_out = fopen("out.txt", "w");
158 fprintf(file_out, "%d\n", S);
159 for (int i = 0; i <= M; ++i)
160 {
161 fprintf(file_out, "%d\n", IC[i]);
162 }
163 for (int j = 1; j <= S; ++j)
164 {
165 fprintf(file_out, "%d %d\n", IX[j - 1], IY[j - 1]);
166 }
167 fclose(file_out);
168 simulate();
169 return 0;
170 }
98
99 void wrong_answer(const char *MSG)
100 {
101 printf("Wrong Answer: %s\n", MSG);
102 exit(0);
103 }
104
105 void simulate()
106 {
107 if (S > S_MAX)
108 {
109 char str[50];
110 sprintf(str, "over %d switches", S_MAX);
111 wrong_answer(str);
112 }
113
114 for (int i = 0; i <= M; ++i)
115 {
116 if (!(-S <= IC[i] && IC[i] <= M))
117 {
118 wrong_answer("wrong serial number");
119 }
120 }
121
122 for (int j = 1; j <= S; ++j)
123 {
124 if (!(-S <= IX[j - 1] && IX[j - 1] <= M))
125 {
126 wrong_answer("wrong serial number");
127 }
128 if (!(-S <= IY[j - 1] && IY[j - 1] <= M))
129 {
130 wrong_answer("wrong serial number");
131 }
132 }
133
134 int P = 0;
135 std::vector<bool> state(S + 1, false);
136 int pos = IC[0];
137 int k = 0;
138
139 FILE *file_log = fopen("log.txt", "w");
140 fprintf(file_log, "0\n");
141
142 for (;;)
143 {
144 fprintf(file_log, "%d\n", pos);
145 if (pos < 0)
146 {
147 if (++P > P_MAX)
148 {
149 fclose(file_log);
150 char str[50];
151 sprintf(str, "over %d inversions", P_MAX);
152 wrong_answer(str);
153 }
154
155 state[-pos] = !state[-pos];
156 pos = state[-pos] ? IX[-(1 + pos)] : IY[-(1 + pos)];
157 }
158 else
159 {
160 if (pos == 0)
161 {
162 break;
163 }
164
165 if (k >= N)
166 {
167 fclose(file_log);
168 wrong_answer("wrong motion");
169 }
170
171 if (pos != A[k++])
172 {
173 fclose(file_log);
CAPITOLUL 3. IOI 2018 326
32 {
33 X[cur_vtx] = -vtx_number - 1;
34 dfs(s, m, v, d + 1);
35 }
36
37 Y[cur_vtx] = -vtx_number - 1;
38 dfs(m+1, e, v ^ (1 << d), d + 1);
39 }
40
41 void create_circuit(int M, std::vector<int> A)
42 {
43 if(A.size() == 1)
44 {
45 vector<int> C(M + 1, 0), X, Y;
46 C[0] = A[0];
47 answer(C, X, Y);
48 return;
49 }
50
51 vector<int> C(M + 1, -1);
52 C[0] = A[0];
53 int K = 0;
54 while((1 << K) < A.size()) K++;
55 total_leaf = (1 << K) - A.size();
56 A.erase(A.begin());
57 A.push_back(0);
58
59 dfs(0, (1 << K) - 1, 0, 0);
60
61 for(int i=0; i<vtx_number; i++)
62 {
63 if(X[i] >= 0) mp[X[i]] = 1;
64 if(Y[i] >= 0) mp[Y[i]] = 1;
65 }
66
67 int ptr = 0;
68 for(int i=0; i<(1<<K); i++)
69 {
70 if(mp[i])
71 {
72 mp[i] = A[ptr++];
73 }
74 }
75
76 for(int i=0; i<vtx_number; i++)
77 {
78 if(X[i] >= 0) X[i] = mp[X[i]];
79 if(Y[i] >= 0) Y[i] = mp[Y[i]];
80 }
81 vector<int> vx(X, X + vtx_number);
82 vector<int> vy(Y, Y + vtx_number);
83 answer(C, vx, vy);
84 }
85
86 //-------------- start grader ------------------
87
88 namespace
89 {
90 constexpr int P_MAX = 20000000;
91 constexpr int S_MAX = 400000;
92
93 int M, N;
94 std::vector<int> A;
95
96 bool answered;
97 int S;
98 std::vector<int> IC, IX, IY;
99
100 int read_int()
101 {
102 int x;
103 if (scanf("%d", &x) != 1)
104 {
105 fprintf(stderr, "Error while reading input\n");
106 exit(1);
107 }
CAPITOLUL 3. IOI 2018 329
108 return x;
109 }
110
111 void wrong_answer(const char *MSG)
112 {
113 printf("Wrong Answer: %s\n", MSG);
114 exit(0);
115 }
116
117 void simulate()
118 {
119 if (S > S_MAX)
120 {
121 char str[50];
122 sprintf(str, "over %d switches", S_MAX);
123 wrong_answer(str);
124 }
125
126 for (int i = 0; i <= M; ++i)
127 {
128 if (!(-S <= IC[i] && IC[i] <= M))
129 {
130 wrong_answer("wrong serial number");
131 }
132 }
133
134 for (int j = 1; j <= S; ++j)
135 {
136 if (!(-S <= IX[j - 1] && IX[j - 1] <= M))
137 {
138 wrong_answer("wrong serial number");
139 }
140 if (!(-S <= IY[j - 1] && IY[j - 1] <= M))
141 {
142 wrong_answer("wrong serial number");
143 }
144 }
145
146 int P = 0;
147 std::vector<bool> state(S + 1, false);
148 int pos = IC[0];
149 int k = 0;
150
151 FILE *file_log = fopen("log.txt", "w");
152 fprintf(file_log, "0\n");
153
154 for (;;)
155 {
156 fprintf(file_log, "%d\n", pos);
157 if (pos < 0)
158 {
159 if (++P > P_MAX)
160 {
161 fclose(file_log);
162 char str[50];
163 sprintf(str, "over %d inversions", P_MAX);
164 wrong_answer(str);
165 }
166
167 state[-pos] = !state[-pos];
168 pos = state[-pos] ? IX[-(1 + pos)] : IY[-(1 + pos)];
169 }
170 else
171 {
172 if (pos == 0)
173 {
174 break;
175 }
176
177 if (k >= N)
178 {
179 fclose(file_log);
180 wrong_answer("wrong motion");
181 }
182
183 if (pos != A[k++])
CAPITOLUL 3. IOI 2018 330
184 {
185 fclose(file_log);
186 wrong_answer("wrong motion");
187 }
188
189 pos = IC[pos];
190 }
191 }
192
193 fclose(file_log);
194
195 if (k != N)
196 {
197 wrong_answer("wrong motion");
198 }
199
200 for (int j = 1; j <= S; ++j)
201 {
202 if (state[j])
203 {
204 wrong_answer("state ’Y’");
205 }
206 }
207
208 printf("Accepted: %d %d\n", S, P);
209 }
210 } // namespace
211
212 void answer(std::vector<int> C, std::vector<int> X, std::vector<int> Y)
213 {
214 if (answered)
215 {
216 wrong_answer("answered not exactly once");
217 }
218
219 answered = true;
220 // check if input format is correct
221 if ((int)C.size() != M + 1)
222 {
223 wrong_answer("wrong array length");
224 }
225
226 if (X.size() != Y.size())
227 {
228 wrong_answer("wrong array length");
229 }
230
231 S = X.size();
232 IC = C;
233 IX = X;
234 IY = Y;
235 }
236
237 int main()
238 {
239 std::freopen("../in/03-04.txt", "r", stdin);
240 //std::freopen("doll.out", "w", stdout);
241
242 auto t1 = clock();
243
244 M = read_int();
245 N = read_int();
246 A.resize(N);
247 for (int k = 0; k < N; ++k)
248 {
249 A[k] = read_int();
250 }
251 fclose(stdin);
252
253 auto t2 = clock();
254
255 answered = false;
256 create_circuit(M, A);
257 if (!answered)
258 {
259 wrong_answer("answered not exactly once");
CAPITOLUL 3. IOI 2018 331
260 }
261
262 auto t3 = clock();
263
264 FILE *file_out = fopen("out.txt", "w");
265 fprintf(file_out, "%d\n", S);
266
267 for (int i = 0; i <= M; ++i)
268 {
269 fprintf(file_out, "%d\n", IC[i]);
270 }
271
272 for (int j = 1; j <= S; ++j)
273 {
274 fprintf(file_out, "%d %d\n", IX[j - 1], IY[j - 1]);
275 }
276
277 fclose(file_out);
278
279 auto t4 = clock();
280
281 simulate();
282
283 auto t5 = clock();
284
285 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
286 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
287 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
288 std::cout <<"t5-t4 = " << (double)(t5 - t4) / CLOCKS_PER_SEC << ’\n’;
289
290 return 0;
291 }
292 //-------------- end grader ------------------
293 /*
294 Accepted: 200006 3836160
295 t2-t1 = 0.359
296 t3-t2 = 0.016
297 t4-t3 = 0.328
298 t5-t4 = 3.714
299
300 Process returned 0 (0x0) execution time : 4.449 s
301 Press any key to continue.
302 */
106 swap(sw[-node][0],sw[-node][1]);
107 node = -1;
108 }
109 else
110 {
111 swap(sw[-node][0],sw[-node][1]);
112 node = sw[-node][1];
113 }
114 }
115
116
117 vector<int> X(-last_switch),Y(-last_switch),C(M + 1);
118
119 for(int i = 0;i <= M;i++)
120 {
121 C[i] = trig[i];
122 }
123
124
125 for(int i = 0;i < -last_switch;i++)
126 {
127 X[i] = sw[i + 1][0];
128 Y[i] = sw[i + 1][1];
129 }
130
131 answer(C,X,Y);
132 }
133 //-------------- start grader ------------------
134
135 namespace
136 {
137
138 constexpr int P_MAX = 20000000;
139 constexpr int S_MAX = 400000;
140
141 int M, N;
142 std::vector<int> A;
143
144 bool answered;
145 int S;
146 std::vector<int> IC, IX, IY;
147
148 int read_int()
149 {
150 int x;
151 if (scanf("%d", &x) != 1)
152 {
153 fprintf(stderr, "Error while reading input\n");
154 exit(1);
155 }
156 return x;
157 }
158
159 void wrong_answer(const char *MSG)
160 {
161 printf("Wrong Answer: %s\n", MSG);
162 exit(0);
163 }
164
165 void simulate()
166 {
167 if (S > S_MAX)
168 {
169 char str[50];
170 sprintf(str, "over %d switches", S_MAX);
171 wrong_answer(str);
172 }
173
174 for (int i = 0; i <= M; ++i)
175 {
176 if (!(-S <= IC[i] && IC[i] <= M))
177 {
178 wrong_answer("wrong serial number");
179 }
180 }
181
CAPITOLUL 3. IOI 2018 334
258 } // namespace
259
260 void answer(std::vector<int> C, std::vector<int> X, std::vector<int> Y)
261 {
262 if (answered)
263 {
264 wrong_answer("answered not exactly once");
265 }
266
267 answered = true;
268 // check if input format is correct
269 if ((int)C.size() != M + 1)
270 {
271 wrong_answer("wrong array length");
272 }
273
274 if (X.size() != Y.size())
275 {
276 wrong_answer("wrong array length");
277 }
278
279 S = X.size();
280 IC = C;
281 IX = X;
282 IY = Y;
283 }
284
285 int main()
286 {
287 std::freopen("../in/03-04.txt", "r", stdin);
288 //std::freopen("doll.out", "w", stdout);
289
290 auto t1 = clock();
291
292 M = read_int();
293 N = read_int();
294 A.resize(N);
295 for (int k = 0; k < N; ++k)
296 {
297 A[k] = read_int();
298 }
299 fclose(stdin);
300
301 auto t2 = clock();
302
303 answered = false;
304 create_circuit(M, A);
305 if (!answered)
306 {
307 wrong_answer("answered not exactly once");
308 }
309
310 auto t3 = clock();
311
312 FILE *file_out = fopen("out.txt", "w");
313 fprintf(file_out, "%d\n", S);
314
315 for (int i = 0; i <= M; ++i)
316 {
317 fprintf(file_out, "%d\n", IC[i]);
318 }
319
320 for (int j = 1; j <= S; ++j)
321 {
322 fprintf(file_out, "%d %d\n", IX[j - 1], IY[j - 1]);
323 }
324
325 fclose(file_out);
326
327 auto t4 = clock();
328
329 simulate();
330
331 auto t5 = clock();
332
333 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
CAPITOLUL 3. IOI 2018 336
334 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
335 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
336 std::cout <<"t5-t4 = " << (double)(t5 - t4) / CLOCKS_PER_SEC << ’\n’;
337
338 return 0;
339 }
340 //-------------- end grader ------------------
341 /*
342 Accepted: 200006 3836160
343 t2-t1 = 0.406
344 t3-t2 = 0.219
345 t4-t3 = 0.296
346 t5-t4 = 3.227
347
348 Process returned 0 (0x0) execution time : 4.196 s
349 Press any key to continue.
350 */
55
56 void create_circuit(int M, std::vector<int> A)
57 {
58 vector<int> C(M + 1, -1);
59
60 int maxlg = 0;
61 int N = A.size();
62 while((1 << maxlg) <= N)
63 ++maxlg;
64 lastid = -maxlg;
65
66 dfs(maxlg - 1, N, 0, 0, 0);
67
68 sort(poz.begin(), poz.end());
69
70 for(int i = 0; i < poz.size(); ++i)
71 {
72 if(poz[i].second.first)
73 Y[-poz[i].second.second - 1] = A[i];
74 else
75 X[-poz[i].second.second - 1] = A[i];
76 }
77
78 answer(C, X, Y);
79 }
80
81 //-------------- start grader ------------------
82
83 namespace
84 {
85
86 constexpr int P_MAX = 20000000;
87 constexpr int S_MAX = 400000;
88
89 int M, N;
90 std::vector<int> A;
91
92 bool answered;
93 int S;
94 std::vector<int> IC, IX, IY;
95
96 int read_int()
97 {
98 int x;
99 if (scanf("%d", &x) != 1)
100 {
101 fprintf(stderr, "Error while reading input\n");
102 exit(1);
103 }
104 return x;
105 }
106
107 void wrong_answer(const char *MSG)
108 {
109 printf("Wrong Answer: %s\n", MSG);
110 exit(0);
111 }
112
113 void simulate()
114 {
115 if (S > S_MAX)
116 {
117 char str[50];
118 sprintf(str, "over %d switches", S_MAX);
119 wrong_answer(str);
120 }
121
122 for (int i = 0; i <= M; ++i)
123 {
124 if (!(-S <= IC[i] && IC[i] <= M))
125 {
126 wrong_answer("wrong serial number");
127 }
128 }
129
130 for (int j = 1; j <= S; ++j)
CAPITOLUL 3. IOI 2018 338
131 {
132 if (!(-S <= IX[j - 1] && IX[j - 1] <= M))
133 {
134 wrong_answer("wrong serial number");
135 }
136 if (!(-S <= IY[j - 1] && IY[j - 1] <= M))
137 {
138 wrong_answer("wrong serial number");
139 }
140 }
141
142 int P = 0;
143 std::vector<bool> state(S + 1, false);
144 int pos = IC[0];
145 int k = 0;
146
147 FILE *file_log = fopen("log.txt", "w");
148 fprintf(file_log, "0\n");
149
150 for (;;)
151 {
152 fprintf(file_log, "%d\n", pos);
153 if (pos < 0)
154 {
155 if (++P > P_MAX)
156 {
157 fclose(file_log);
158 char str[50];
159 sprintf(str, "over %d inversions", P_MAX);
160 wrong_answer(str);
161 }
162
163 state[-pos] = !state[-pos];
164 pos = state[-pos] ? IX[-(1 + pos)] : IY[-(1 + pos)];
165 }
166 else
167 {
168 if (pos == 0)
169 {
170 break;
171 }
172
173 if (k >= N)
174 {
175 fclose(file_log);
176 wrong_answer("wrong motion");
177 }
178
179 if (pos != A[k++])
180 {
181 fclose(file_log);
182 wrong_answer("wrong motion");
183 }
184
185 pos = IC[pos];
186 }
187 }
188
189 fclose(file_log);
190
191 if (k != N)
192 {
193 wrong_answer("wrong motion");
194 }
195
196 for (int j = 1; j <= S; ++j)
197 {
198 if (state[j])
199 {
200 wrong_answer("state ’Y’");
201 }
202 }
203
204 printf("Accepted: %d %d\n", S, P);
205 }
206 } // namespace
CAPITOLUL 3. IOI 2018 339
207
208 void answer(std::vector<int> C, std::vector<int> X, std::vector<int> Y)
209 {
210 if (answered)
211 {
212 wrong_answer("answered not exactly once");
213 }
214
215 answered = true;
216 // check if input format is correct
217 if ((int)C.size() != M + 1)
218 {
219 wrong_answer("wrong array length");
220 }
221
222 if (X.size() != Y.size())
223 {
224 wrong_answer("wrong array length");
225 }
226
227 S = X.size();
228 IC = C;
229 IX = X;
230 IY = Y;
231 }
232
233 int main()
234 {
235 std::freopen("../in/03-04.txt", "r", stdin);
236 //std::freopen("doll.out", "w", stdout);
237
238 auto t1 = clock();
239
240 M = read_int();
241 N = read_int();
242 A.resize(N);
243 for (int k = 0; k < N; ++k)
244 {
245 A[k] = read_int();
246 }
247 fclose(stdin);
248
249 auto t2 = clock();
250
251 answered = false;
252 create_circuit(M, A);
253 if (!answered)
254 {
255 wrong_answer("answered not exactly once");
256 }
257
258 auto t3 = clock();
259
260 FILE *file_out = fopen("out.txt", "w");
261 fprintf(file_out, "%d\n", S);
262
263 for (int i = 0; i <= M; ++i)
264 {
265 fprintf(file_out, "%d\n", IC[i]);
266 }
267
268 for (int j = 1; j <= S; ++j)
269 {
270 fprintf(file_out, "%d %d\n", IX[j - 1], IY[j - 1]);
271 }
272
273 fclose(file_out);
274
275 auto t4 = clock();
276
277 simulate();
278
279 auto t5 = clock();
280
281 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
282 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
CAPITOLUL 3. IOI 2018 340
283 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
284 std::cout <<"t5-t4 = " << (double)(t5 - t4) / CLOCKS_PER_SEC << ’\n’;
285
286 return 0;
287 }
288 //-------------- end grader ------------------
289 /*
290 Accepted: 200006 3836160
291 t2-t1 = 0.343
292 t3-t2 = 0.36
293 t4-t3 = 0.312
294 t5-t4 = 3.656
295
296 Process returned 0 (0x0) execution time : 4.703 s
297 Press any key to continue.
298 */
Î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 ecare din autostr zi. Taxa pe autostrad depinde
de condiµiile de trac. Tracul poate relaxat sau intens. Când tracul este relaxat taxa este
de A yen (valut japonez ). Când tracul 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 tracului 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 trac specicate.
Totu³i, dispozitivul este doar un prototip. Valorile S ³i T sunt xate (adic în echipament)
³i necunoscute. Trebuie s determinaµi valorile S ³i T . Pentru a realiza aceasta, planicaµi s
specicaµi dispozitivului anumite condiµii de trac ³i s folosiµi valorile taxelor calculate de acesta
pentru a deduce S ³i T . Deoarece specicarea condiµiilor de trac cost , nu doriµi s folosiµi
dispozitivul de multe ori.
Detalii de implementare
a Pentru ecare i (0 & i & M 1), w i descrie condiµiile de trac pe autostrada i. Valoarea
wi trebuie s e 0 sau 1.
` w[i] = 0 înseamn c tracul pe autostrada i este relaxat.
` w[i] = 1 înseamn c tracul 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 trac specicate de w.
a Aceast funcµie poate apelat de cel mult 100 de ori (pentru ecare test).
Exemple
În gura 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]), tracul pe ecare 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 3. IOI 2018 342
Subtaskuri
Exemplu de grader
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 3. IOI 2018 344
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 nd s and t as in the last part of Subtask 4.
20
21 int read_int()
22 {
23 int x;
24 if (scanf("%d", &x) != 1)
25 {
26 fprintf(stderr, "Error while reading input\n");
27 exit(1);
28 }
29 return x;
30 }
31
32 void wrong_answer(const char *MSG)
33 {
34 printf("Wrong Answer: %s\n", MSG);
35 exit(0);
36 }
37
38 } // namespace
39
40 long long ask(const std::vector<int> &w)
41 {
42 if (++num_calls > MAX_NUM_CALLS)
43 {
44 wrong_answer("more than 100 calls to ask");
45 }
46 if (w.size() != (size_t)M)
47 {
48 wrong_answer("w is invalid");
49 }
50 for (size_t i = 0; i < w.size(); ++i)
51 {
52 if (!(w[i] == 0 || w[i] == 1))
53 {
54 wrong_answer("w is invalid");
55 }
56 }
57
58 std::vector<bool> visited(N, false);
59 std::vector<long long> current_dist(N, INF);
60 std::queue<int> qa, qb;
61 qa.push(S);
62 current_dist[S] = 0;
63 while (!qa.empty() || !qb.empty())
64 {
65 int v;
66 if (qb.empty() ||
67 (!qa.empty() && current_dist[qa.front()] <=
68 current_dist[qb.front()]))
69 {
70 v = qa.front();
71 qa.pop();
72 }
73 else
74 {
75 v = qb.front();
76 qb.pop();
77 }
78 if (visited[v])
79 {
80 continue;
81 }
82 visited[v] = true;
83 long long d = current_dist[v];
84 if (v == T)
85 {
86 return d;
87 }
88 for (auto e : graph[v])
89 {
90 int vv = e.first;
91 int ei = e.second;
92 if (!visited[vv])
93 {
94 if (w[ei] == 0)
95 {
CAPITOLUL 3. IOI 2018 346
96 if (current_dist[vv] > d + A)
97 {
98 current_dist[vv] = d + A;
99 qa.push(vv);
100 }
101 }
102 else
103 {
104 if (current_dist[vv] > d + B)
105 {
106 current_dist[vv] = d + B;
107 qb.push(vv);
108 }
109 }
110 }
111 }
112 }
113 return -1;
114 }
115
116 void answer(int s, int t)
117 {
118 if (answered)
119 {
120 wrong_answer("answered not exactly once");
121 }
122
123 if (!((s == S && t == T) || (s == T && t == S)))
124 {
125 wrong_pair = true;
126 }
127
128 answered = true;
129 }
130
131 int main()
132 {
133 N = read_int();
134 M = read_int();
135 A = read_int();
136 B = read_int();
137 S = read_int();
138 T = read_int();
139
140 U.resize(M);
141 V.resize(M);
142 graph.assign(N, std::vector<std::pair<int, int>>());
143
144 for (int i = 0; i < M; ++i)
145 {
146 U[i] = read_int();
147 V[i] = read_int();
148 graph[U[i]].push_back({V[i], i});
149 graph[V[i]].push_back({U[i], i});
150 }
151
152 answered = false;
153 wrong_pair = false;
154 num_calls = 0;
155 find_pair(N, U, V, A, B);
156
157 if (!answered)
158 {
159 wrong_answer("answered not exactly once");
160 }
161 if (wrong_pair)
162 {
163 wrong_answer("{s, t} is wrong");
164 }
165 printf("Accepted: %d\n", num_calls);
166 return 0;
167 }
1 // https://oj.uz/submission/74962
2
3 //#include <ctime>
4 #include <time.h> /* clock */
5
6 //#include <cstdio>
7 #include <stdio.h> // citire mai rapida !!!
8
9 #include<bits/stdc++.h>
10
11 #include "highway.h"
12
13 #define X first
14 #define Y second
15
16 using namespace std;
17
18 typedef long long ll;
19 typedef pair<int,int> pii;
20 typedef pair<ll,ll> pll;
21
22 const int NN = 90005;
23 const int MM = 1300005;
24
25 const ll inf = 1e18;
26
27 int n, m, a, b, p;
28 ll def, dis[NN];
29 bool ban[NN], v1[NN], v2[NN];
30
31 vector<int> adj[NN], dij[NN], drv[NN], ord;
32 vector<pii> edg;
33
34 queue<int> q;
35
36 ll query ()
37 {
38 vector<int> V;
39 for(int i=0;i<m;i++)
40 {
41 V.push_back(ban[edg[i].X] || ban[edg[i].Y]);
42 }
43 return ask(V);
44 }
45
46 int getpiv ()
47 {
48 int S = 0, E = (int)ord.size() - 1;
49 while(S<E)
50 {
51 int Z = (S+E)/2;
52 for(int i=0;i<=Z;i++)
53 {
54 ban[ord[i]] = true;
55 }
56 query() != def ? E = Z : S = Z+1;
57 for(int i=0;i<=Z;i++)
58 {
59 ban[ord[i]] = false;
60 }
61 }
62 return ord[S];
63 }
64
65 void dfs1 (int C)
66 {
67 if(C == p || v1[C]) return;
68 v1[C] = true;
69 for(auto &T : drv[C])
70 {
71 dfs1(T);
72 }
73 }
74
75 void dfs2 (int C)
76 {
CAPITOLUL 3. IOI 2018 348
77 if(v2[C]) return;
78 v2[C] = true;
79 for(auto &T : dij[C])
80 {
81 dfs2(T);
82 }
83 }
84
85 void find_pair(int _N, vector<int> _U, vector<int> _V, int _A, int _B)
86 {
87 n = _N;
88 m = (int)_U.size();
89 a = _A;
90 b = _B;
91 for(int i=0;i<m;i++)
92 {
93 edg.push_back({_U[i]+1, _V[i]+1});
94 adj[_U[i]+1].push_back(_V[i]+1);
95 adj[_V[i]+1].push_back(_U[i]+1);
96 }
97 def = query();
98 for(int i=1;i<=n;i++)
99 {
100 ord.push_back(i);
101 }
102 p = getpiv();
103 ord.clear();
104 for(int i=1;i<p;i++)
105 {
106 ban[i] = true;
107 }
108 for(int i=1;i<=n;i++)
109 {
110 dis[i] = inf;
111 }
112 dis[p] = 0;
113 q.push(p);
114 while(!q.empty())
115 {
116 int C = q.front();
117 q.pop();
118 ord.push_back(C);
119 for(auto &T : adj[C])
120 {
121 if(T < p) continue;
122 if(dis[T] == inf)
123 {
124 dis[T] = dis[C] + 1;
125 q.push(T);
126 }
127 if(dis[T] == dis[C] - 1)
128 {
129 dij[T].push_back(C);
130 drv[C].push_back(T);
131 }
132 }
133 }
134 reverse(ord.begin(), ord.end());
135 int PA = getpiv();
136 ord.clear();
137 dfs1(PA);
138 for(int i=p;i<=n;i++)
139 {
140 if(v1[i]) dfs2(i);
141 }
142 for(int i=p;i<=n;i++)
143 {
144 if(!v2[i] && dis[i] + dis[PA] == def / a) ord.push_back(i);
145 }
146 int PB = getpiv();
147 ord.clear();
148 answer(PA-1, PB-1);
149 }
150
151 //-------------- start grader ------------------
152
CAPITOLUL 3. IOI 2018 349
153 namespace
154 {
155 constexpr int MAX_NUM_CALLS = 100;
156 constexpr long long INF = 1LL << 61;
157
158 int N, M, A, B, S, T;
159 std::vector<int> U, V;
160 std::vector<std::vector<std::pair<int, int>>> graph;
161
162 bool answered, wrong_pair;
163 int num_calls;
164
165 int read_int()
166 {
167 int x;
168 if (scanf("%d", &x) != 1)
169 {
170 fprintf(stderr, "Error while reading input\n");
171 exit(1);
172 }
173 return x;
174 }
175
176 void wrong_answer(const char *MSG)
177 {
178 printf("Wrong Answer: %s\n", MSG);
179 exit(0);
180 }
181
182 } // namespace
183
184 long long ask(const std::vector<int> &w)
185 {
186 if (++num_calls > MAX_NUM_CALLS)
187 {
188 wrong_answer("more than 100 calls to ask");
189 }
190 if (w.size() != (size_t)M)
191 {
192 wrong_answer("w is invalid");
193 }
194 for (size_t i = 0; i < w.size(); ++i)
195 {
196 if (!(w[i] == 0 || w[i] == 1))
197 {
198 wrong_answer("w is invalid");
199 }
200 }
201
202 std::vector<bool> visited(N, false);
203 std::vector<long long> current_dist(N, INF);
204 std::queue<int> qa, qb;
205 qa.push(S);
206 current_dist[S] = 0;
207 while (!qa.empty() || !qb.empty())
208 {
209 int v;
210 if (qb.empty() ||
211 (!qa.empty() && current_dist[qa.front()] <= current_dist[qb.front()]))
212 {
213 v = qa.front();
214 qa.pop();
215 }
216 else
217 {
218 v = qb.front();
219 qb.pop();
220 }
221 if (visited[v])
222 {
223 continue;
224 }
225 visited[v] = true;
226 long long d = current_dist[v];
227 if (v == T)
228 {
CAPITOLUL 3. IOI 2018 350
229 return d;
230 }
231 for (auto e : graph[v])
232 {
233 int vv = e.first;
234 int ei = e.second;
235 if (!visited[vv])
236 {
237 if (w[ei] == 0)
238 {
239 if (current_dist[vv] > d + A)
240 {
241 current_dist[vv] = d + A;
242 qa.push(vv);
243 }
244 }
245 else
246 {
247 if (current_dist[vv] > d + B)
248 {
249 current_dist[vv] = d + B;
250 qb.push(vv);
251 }
252 }
253 }
254 }
255 }
256 return -1;
257 }
258
259 void answer(int s, int t)
260 {
261 if (answered)
262 {
263 wrong_answer("answered not exactly once");
264 }
265
266 if (!((s == S && t == T) || (s == T && t == S)))
267 {
268 wrong_pair = true;
269 }
270
271 answered = true;
272 }
273
274 int main()
275 {
276
277 auto t1 = clock();
278
279 std::freopen("../in/06-41.txt", "r", stdin) ;
280 //std::freopen("highway.out", "w", stdout) ;
281
282 N = read_int();
283 M = read_int();
284 A = read_int();
285 B = read_int();
286 S = read_int();
287 T = read_int();
288 U.resize(M);
289 V.resize(M);
290
291 graph.assign(N, std::vector<std::pair<int, int>>());
292
293 for (int i = 0; i < M; ++i)
294 {
295 U[i] = read_int();
296 V[i] = read_int();
297 graph[U[i]].push_back({V[i], i});
298 graph[V[i]].push_back({U[i], i});
299 }
300
301 auto t2 = clock();
302
303 answered = false;
304 wrong_pair = false;
CAPITOLUL 3. IOI 2018 351
305 num_calls = 0;
306
307 find_pair(N, U, V, A, B);
308
309 auto t3 = clock();
310
311 if (!answered)
312 {
313 wrong_answer("answered not exactly once");
314 }
315 if (wrong_pair)
316 {
317 wrong_answer("{s, t} is wrong");
318 }
319 printf("Accepted: %d\n", num_calls);
320
321 auto t4 = clock();
322
323 fclose(stdout);
324
325 // reset console output
326 freopen("CON", "w", stdout);
327
328 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
329 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
330 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
331
332 return 0;
333 }
334 /*
335 Accepted: 39
336 t2-t1 = 0.328
337 t3-t2 = 3.834
338 t4-t3 = 0
339
340 Process returned 0 (0x0) execution time : 4.271 s
341 Press any key to continue.
342 */
35 }
36 vector<int> v(M);
37 lint stdist = ask(v) / A;
38 int s = 0, e = M - 1;
39 while(s != e){
40 int m = (s + e) / 2;
41 fill(v.begin() + m + 1, v.end(), 0);
42 fill(v.begin(), v.begin() + m + 1, 1);
43 if(ask(v) != A * stdist) e = m;
44 else s = m + 1;
45 }
46 vector<int> bord[2], dist(N, 1e9);
47 queue<pi> que;
48 que.emplace(0, U[s]);
49 que.emplace(1, V[s]);
50 dist[U[s]] = dist[V[s]] = 0;
51 while(!que.empty()){
52 auto x = que.front(); que.pop();
53 bord[x.first].push_back(x.second);
54 for(auto &i : gph[x.second]){
55 if(dist[i] > dist[x.second] + 1){
56 dist[i] = dist[x.second] + 1;
57 que.emplace(x.first, i);
58 }
59 }
60 }
61 int S = -1, T = -1;
62 for(int i=0; i<2; i++){
63 s = 0, e = (int)bord[i].size() - 1;
64 while(s != e){
65 int m = (s + e + 1) / 2;
66 vector<int> C(bord[i].begin() + m, bord[i].end());
67 if(cut_ask(M, C, U, V) != stdist * A) s = m;
68 else e = m - 1;
69 }
70 if(i) S = bord[i][s];
71 else T = bord[i][s];
72 }
73 answer(S, T);
74 }
75
76
77
78 //-------------- start grader ------------------
79
80 namespace
81 {
82 constexpr int MAX_NUM_CALLS = 100;
83 constexpr long long INF = 1LL << 61;
84
85 int N, M, A, B, S, T;
86 std::vector<int> U, V;
87 std::vector<std::vector<std::pair<int, int>>> graph;
88
89 bool answered, wrong_pair;
90 int num_calls;
91
92 int read_int()
93 {
94 int x;
95 if (scanf("%d", &x) != 1)
96 {
97 fprintf(stderr, "Error while reading input\n");
98 exit(1);
99 }
100 return x;
101 }
102
103 void wrong_answer(const char *MSG)
104 {
105 printf("Wrong Answer: %s\n", MSG);
106 exit(0);
107 }
108
109 } // namespace
110
CAPITOLUL 3. IOI 2018 353
187 if (answered)
188 {
189 wrong_answer("answered not exactly once");
190 }
191
192 if (!((s == S && t == T) || (s == T && t == S)))
193 {
194 wrong_pair = true;
195 }
196
197 answered = true;
198 }
199
200 int main()
201 {
202
203 auto t1 = clock();
204
205 std::freopen("../in/06-41.txt", "r", stdin) ;
206 //std::freopen("highway.out", "w", stdout) ;
207
208 N = read_int();
209 M = read_int();
210 A = read_int();
211 B = read_int();
212 S = read_int();
213 T = read_int();
214 U.resize(M);
215 V.resize(M);
216
217 graph.assign(N, std::vector<std::pair<int, int>>());
218
219 for (int i = 0; i < M; ++i)
220 {
221 U[i] = read_int();
222 V[i] = read_int();
223 graph[U[i]].push_back({V[i], i});
224 graph[V[i]].push_back({U[i], i});
225 }
226
227 auto t2 = clock();
228
229 answered = false;
230 wrong_pair = false;
231 num_calls = 0;
232
233 find_pair(N, U, V, A, B);
234
235 auto t3 = clock();
236
237 if (!answered)
238 {
239 wrong_answer("answered not exactly once");
240 }
241 if (wrong_pair)
242 {
243 wrong_answer("{s, t} is wrong");
244 }
245 printf("Accepted: %d\n", num_calls);
246
247 auto t4 = clock();
248
249 fclose(stdout);
250
251 // reset console output
252 freopen("CON", "w", stdout);
253
254 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
255 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
256 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
257
258 return 0;
259 }
260 /*
261 Accepted: 45
262 t2-t1 = 0.343
CAPITOLUL 3. IOI 2018 355
67 fill(tr, tr + M, 0);
68 ll DA = ask(Q);
69 while (lo < hi)
70 {
71 mid = lo + (hi - lo) / 2;
72 FOR(i, M) Q[i] = i <= mid;
73 if (ask(Q) == DA) lo = mid + 1;
74 else hi = mid;
75 }
76
77 fill(to, to + N, -1);
78
79 queue<pii> q;
80 q.emplace(U[lo], 0);
81 q.emplace(V[lo], 1);
82
83 tr[lo] = 1;
84 to[U[lo]] = to[V[lo]] = -INT_INF;
85
86 while (!q.empty())
87 {
88 pii v = q.front();
89 q.pop();
90 verts[v.s].pb(v.f);
91 FORE(e, adj[v.f])
92 {
93 int w = v.f ^ U[e] ^ V[e];
94 if (to[w] != -1) continue;
95 q.emplace(w, v.s);
96 tr[to[w] = e] = 1;
97 }
98 }
99
100 FOR(i, 2)
101 {
102 lo = 1, hi = sz(verts[i]) - 1;
103 while (lo <= hi)
104 {
105 mid = lo + (hi - lo) / 2;
106 FOR(j, M) Q[j] = !tr[j];
107 For(j, mid, sz(verts[i])) Q[to[verts[i][j]]] = 1;
108 if (ask(Q) == DA) hi = mid - 1;
109 else lo = mid + 1;
110 }
111 ans[i] = verts[i][hi];
112 }
113 answer(ans[0], ans[1]);
114 }
115
116 //-------------- start grader ------------------
117
118 namespace
119 {
120 constexpr int MAX_NUM_CALLS = 100;
121 constexpr long long INF = 1LL << 61;
122
123 int N, M, A, B, S, T;
124 std::vector<int> U, V;
125 std::vector<std::vector<std::pair<int, int>>> graph;
126
127 bool answered, wrong_pair;
128 int num_calls;
129
130 int read_int()
131 {
132 int x;
133 if (scanf("%d", &x) != 1)
134 {
135 fprintf(stderr, "Error while reading input\n");
136 exit(1);
137 }
138 return x;
139 }
140
141 void wrong_answer(const char *MSG)
142 {
CAPITOLUL 3. IOI 2018 357
219 }
220 }
221 return -1;
222 }
223
224 void answer(int s, int t)
225 {
226 if (answered)
227 {
228 wrong_answer("answered not exactly once");
229 }
230
231 if (!((s == S && t == T) || (s == T && t == S)))
232 {
233 wrong_pair = true;
234 }
235
236 answered = true;
237 }
238
239 int main()
240 {
241
242 auto t1 = clock();
243
244 std::freopen("../in/06-41.txt", "r", stdin) ;
245 //std::freopen("highway.out", "w", stdout) ;
246
247 N = read_int();
248 M = read_int();
249 A = read_int();
250 B = read_int();
251 S = read_int();
252 T = read_int();
253 U.resize(M);
254 V.resize(M);
255
256 graph.assign(N, std::vector<std::pair<int, int>>());
257
258 for (int i = 0; i < M; ++i)
259 {
260 U[i] = read_int();
261 V[i] = read_int();
262 graph[U[i]].push_back({V[i], i});
263 graph[V[i]].push_back({U[i], i});
264 }
265
266 auto t2 = clock();
267
268 answered = false;
269 wrong_pair = false;
270 num_calls = 0;
271
272 find_pair(N, U, V, A, B);
273
274 auto t3 = clock();
275
276 if (!answered)
277 {
278 wrong_answer("answered not exactly once");
279 }
280 if (wrong_pair)
281 {
282 wrong_answer("{s, t} is wrong");
283 }
284 printf("Accepted: %d\n", num_calls);
285
286 auto t4 = clock();
287
288 fclose(stdout);
289
290 // reset console output
291 freopen("CON", "w", stdout);
292
293 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
294 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
CAPITOLUL 3. IOI 2018 359
295 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
296
297 return 0;
298 }
299 /*
300 Accepted: 45
301 t2-t1 = 0.343
302 t3-t2 = 4.04
303 t4-t3 = 0
304
305 Process returned 0 (0x0) execution time : 4.461 s
306 Press any key to continue.
307 */
3.6 Meetings
Problema 6 - Meetings 100 de puncte
Author: Riku Kawasaki (Japan)
Pentru ecare ³edinµ doriµi s g siµi costul minim posibil de organizare a ei.
Luaµi la cuno³tinµ c dup ecare ³edinµ ecare participant se întoarce la muntele lui; deci
costul unei ³edinµe nu este inuenµat de ³edinµele precedente.
Detalii de implementare
Exemple
Restricµii
Subtaskuri
Exemplu de grader
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-rst-search
post-order of the cartesian tree of H .
We dene 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, rst
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 rst 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 .
24 std::vector<int> H(N);
25 for (int i = 0; i < N; ++i)
26 {
27 H[i] = read_int();
28 }
29 std::vector<int> L(Q), R(Q);
30 for (int j = 0; j < Q; ++j)
31 {
32 L[j] = read_int();
33 R[j] = read_int();
34 }
35
36 std::vector<long long> C = minimum_costs(H, L, R);
37
38 for (size_t j = 0; j < C.size(); ++j)
39 {
40 printf("%lld\n", C[j]);
41 }
42 return 0;
43 }
53 for(; l<=r; )
54 {
55 if(l & 1) ret = max(ret, T[l]);
56 if(~r & 1) ret = max(ret, T[r]);
57 l = l + 1 >> 1;
58 r = r - 1 >> 1;
59 }
60
61 return ret.second;
62 }
63 };
64
65 struct line
66 {
67 ll x, a, b;
68 line() {}
69 line(ll x, ll a, ll b) : x(x), a(a), b(b) {}
70 };
71
72 struct deq
73 {
74 line D[808080];
75 int S[808080], E[808080];
76 ll V[808080];
77 int n;
78 bool t;
79
80 void init(bool _t, int _n)
81 {
82 int i;
83 t = _t; n = _n;
84 for(i=0; i<n; i++)
85 {
86 S[i] = i; E[i] = i;
87 D[i] = line(i, 0, 0);
88 }
89 }
90
91 void addval(int p, ll v)
92 {
93 if(t) p = n - 1 - p;
94 V[p] += v;
95 }
96
97 void addline(int p, ll x, ll a, ll b)
98 {
99 if(t)
100 {
101 p = n - 1 - p, x = n - 1 - x;
102 b = (n - 1) * a + b; a = -a;
103 }
104
105 int &s = S[p], &e = E[p];
106
107 b -= V[p];
108
109 for(; s<=e; e--)
110 {
111 if(D[e].a == a && D[e].b < b) return;
112 if(D[e].a * D[e].x + D[e].b < a * D[e].x + b)
113 {
114 D[++e] = line((D[e].b - b) / (a - D[e].a) + 1, a, b);
115 return;
116 }
117 }
118
119 D[++e] = line(x, a, b);
120 }
121
122 ll getval(int p, ll x)
123 {
124 if(t) p = n - 1 - p, x = n - 1 - x;
125
126 int k = upper_bound(D + S[p], D + E[p] + 1, x, [&](ll x, line l)
127 {
128 return x < l.x;
CAPITOLUL 3. IOI 2018 366
129 }) - D - 1;
130
131 return D[k].a * x + D[k].b + V[p];
132 }
133
134 void merge(int p, int q)
135 {
136 if(t) p = n - 1 - p, q = n - 1 - q;
137
138 int i;
139
140 if(E[p] - S[p] < E[q] - S[q])
141 {
142 swap(S[p], S[q]); swap(E[p], E[q]);
143 swap(V[p], V[q]);
144 }
145
146 if(S[p] < S[q])
147 {
148 for(i=S[q]; i<=E[q]; i++)
149 {
150 D[i].b += V[q] - V[p];
151 D[++E[p]] = D[i];
152 }
153 }
154 else
155 {
156 for(i=E[q]; i>=S[q]; i--)
157 {
158 D[i].b += V[q] - V[p];
159 D[--S[p]] = D[i];
160 }
161 }
162 }
163 };
164
165 minseg T;
166 deq DL, DR;
167
168 vector <int> H, L, R;
169 vector <int> Q[808080];
170 vector <ll> A;
171
172 int n;
173
174 int dnc(int s, int e)
175 {
176 if(s > e) return -1;
177
178 int m, l, r;
179 ll v, h;
180
181 m = T.getmax(s, e); h = H[m];
182 l = dnc(s, m - 1); r = dnc(m + 1, e);
183
184 for(int &q: Q[m])
185 {
186 if(L[q] == m && R[q] == m) A[q] = h;
187 else if(L[q] == m) A[q] = DR.getval(r, R[q]) + h;
188 else if(R[q] == m) A[q] = DL.getval(l, L[q]) + h;
189 else A[q] = min(DL.getval(l, L[q]) + h * (R[q] - m + 1),
190 DR.getval(r, R[q]) + h * (m - L[q] + 1));
191 }
192
193 if(l != -1) DL.merge(m, l);
194 DL.addval(m, h * (e - m + 1));
195 DL.addline(m, s, -h, (r != -1? DL.getval(r, m + 1) : 0) + h * (m + 1));
196 if(r != -1) DL.merge(m, r);
197
198 if(r != -1) DR.merge(m, r);
199 DR.addval(m, h * (m - s + 1));
200 DR.addline(m, e, h, (l != -1? DR.getval(l, m - 1) : 0) - h * (m - 1));
201 if(l != -1) DR.merge(m, l);
202
203 return m;
204 }
CAPITOLUL 3. IOI 2018 367
205
206 vector <ll> minimum_costs(vector <int> _H, vector <int> _L, vector <int> _R)
207 {
208 int i;
209
210 swap(H, _H); swap(L, _L); swap(R, _R);
211 n = H.size(); A.resize(L.size());
212
213 T.init(H); DL.init(0, n); DR.init(1, n);
214
215 for(i=0; i<L.size(); i++)
216 {
217 Q[T.getmax(L[i], R[i])].push_back(i);
218 }
219
220 dnc(0, n - 1);
221
222 return A;
223 }
224 // =======================================================================
225 int main()
226 {
227 auto t1 = clock();
228
229 std::freopen("../in/05-03.txt", "r", stdin) ;
230 std::freopen("meetings.out", "w", stdout) ;
231
232 int N = read_int();
233 int Q = read_int();
234 std::vector<int> H(N);
235 for (int i = 0; i < N; ++i) {
236 H[i] = read_int();
237 }
238 std::vector<int> L(Q), R(Q);
239 for (int j = 0; j < Q; ++j)
240 {
241 L[j] = read_int();
242 R[j] = read_int();
243 }
244
245 auto t2 = clock();
246
247 std::vector<long long> C = minimum_costs(H, L, R);
248
249 auto t3 = clock();
250
251 for (size_t j = 0; j < C.size(); ++j)
252 {
253 printf("%lld\n", C[j]);
254 }
255
256 auto t4 = clock();
257
258 fclose(stdout);
259
260 // reset console output
261 freopen("CON", "w", stdout);
262
263 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
264 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
265 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
266
267 return 0;
268 }
269 // =======================================================================
270 /*
271 t2-t1 = 4.192
272 t3-t2 = 2.416
273 t4-t3 = 0.97
274
275 Process returned 0 (0x0) execution time : 8.449 s
276 Press any key to continue.
277 */
1 // https://oj.uz/submission/76204
2
3 #include <stdio.h> // citire mai rapida !!!
4
5 #include <bits/stdc++.h>
6
7 using namespace std;
8
9 typedef long long llong;
10 typedef pair<int, int> pii;
11
12 int n;
13
14 const llong inf = 1e18;
15 vector<llong> ans;
16 pii seg[1 << 21];
17
18 struct query
19 {
20 int i, l, r;
21 query(int i, int l, int r) : i(i), l(l), r(r) {}
22 };
23
24 vector<query> qs[750001];
25 pii arr[750001];
26
27 void init(int i, int s, int e)
28 {
29 if (s == e)
30 {
31 seg[i] = arr[s];
32 return;
33 }
34 int m = (s + e) / 2;
35 init(i << 1, s, m);
36 init(i << 1 | 1, m + 1, e);
37 seg[i] = max(seg[i << 1], seg[i << 1 | 1]);
38 }
39
40 pii getMax(int i, int s, int e, int x, int y)
41 {
42 if (e < x || y < s) return pii(0, 0);
43 if (x <= s && e <= y) return seg[i];
44 int m = (s + e) / 2;
45 return max(getMax(i << 1, s,m,x,y), getMax(i << 1 | 1, m+1,e,x,y));
46 }
47
48 struct line
49 {
50 int s, e;
51 llong m, b;
52 line() {}
53 line(int s, int e, llong m, llong b) : s(s), e(e), m(m), b(b) {}
54
55 llong get(int x) const
56 {
57 return m * x + b;
58 }
59
60 bool operator<=(const line &p) const
61 {
62 return get(p.s) <= p.get(p.s) && get(p.e) <= p.get(p.e);
63 }
64 } ls[750001];
65
66 struct que
67 {
68 int s, e;
69 llong add;
70 que(int s, int e) : s(s), e(e), add(0) {}
71 llong getRight() const
72 {
73 if (s > e) return 0;
74 return ls[e].get(ls[e].e) + add;
75 }
CAPITOLUL 3. IOI 2018 369
152 {
153 while (L.size())
154 {
155 R.push_front(L.back());
156 L.pop_back();
157 }
158 return R;
159 }
160 else
161 {
162 while (R.size())
163 {
164 L.push_back(R.front());
165 R.pop_front();
166 }
167 return L;
168 }
169 }
170
171 vector<llong> minimum_costs(vector<int> H, vector<int> L, vector<int> R)
172 {
173 n = H.size();
174 int q = L.size();
175 ans.resize(q, inf);
176
177 for (int i = 0; i < n; ++i) arr[i + 1] = pii(H[i], i + 1);
178 init(1, 1, n);
179 for (int i = 0; i < q; ++i)
180 {
181 int mx = getMax(1, 1, n, L[i] + 1, R[i] + 1).second;
182 qs[mx].emplace_back(i, L[i] + 1, R[i] + 1);
183 }
184 getQuery(1, n);
185
186 for (int i = 1; i <= n; ++i) qs[i].clear();
187
188 for (int i = 0; i < n; ++i) arr[n - i] = pii(H[i], i - n);
189 init(1, 1, n);
190 for (int i = 0; i < q; ++i)
191 {
192 int mx = -getMax(1, 1, n, n - R[i], n - L[i]).second;
193 qs[mx].emplace_back(i, n - R[i], n - L[i]);
194 }
195 getQuery(1, n);
196 return ans;
197 }
198
199 //-------------- start grader ------------------
200
201 namespace
202 {
203 int read_int()
204 {
205 int x;
206 if (scanf("%d", &x) != 1)
207 {
208 fprintf(stderr, "Error while reading input\n");
209 exit(1);
210 }
211 return x;
212 }
213 } // namespace
214
215 int main()
216 {
217 std::freopen("../in/05-12.txt", "r", stdin);
218 std::freopen("meetings.out", "w", stdout);
219
220 auto t1 = clock();
221
222 int N = read_int();
223 int Q = read_int();
224 std::vector<int> H(N);
225 for (int i = 0; i < N; ++i)
226 {
227 H[i] = read_int();
CAPITOLUL 3. IOI 2018 371
228 }
229 std::vector<int> L(Q), R(Q);
230 for (int j = 0; j < Q; ++j)
231 {
232 L[j] = read_int();
233 R[j] = read_int();
234 }
235
236 fclose(stdin);
237 auto t2 = clock();
238
239 std::vector<long long> C = minimum_costs(H, L, R);
240
241 auto t3 = clock();
242
243 for (size_t j = 0; j < C.size(); ++j)
244 {
245 printf("%lld\n", C[j]);
246 }
247
248 auto t4 = clock();
249
250 // reset console output
251 freopen("CON", "w", stdout);
252
253 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
254 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
255 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
256
257 return 0;
258 }
259 /*
260 t2-t1 = 1.205
261 t3-t2 = 11.063
262 t4-t3 = 0.765
263
264 Process returned 0 (0x0) execution time : 13.340 s
265 Press any key to continue.
266 */
34 }
35 }
36
37 int getmax(int l, int r)
38 {
39 pii ret(-1, -1);
40
41 l += sz; r += sz;
42 for(; l<=r; )
43 {
44 if(l & 1) ret = max(ret, T[l]);
45 if(~r & 1) ret = max(ret, T[r]);
46 l = l + 1 >> 1;
47 r = r - 1 >> 1;
48 }
49
50 return ret.second;
51 }
52 };
53
54 struct line
55 {
56 ll x, a, b;
57 line() {}
58 line(ll x, ll a, ll b) : x(x), a(a), b(b) {}
59 };
60
61 struct deq
62 {
63 line D[808080];
64 int S[808080], E[808080];
65 ll V[808080];
66 int n;
67 bool t;
68
69 void init(bool _t, int _n)
70 {
71 int i;
72
73 t = _t; n = _n;
74
75 for(i=0; i<n; i++)
76 {
77 S[i] = i; E[i] = i;
78 D[i] = line(i, 0, 0);
79 }
80 }
81
82 void addval(int p, ll v)
83 {
84 if(t) p = n - 1 - p;
85 V[p] += v;
86 }
87
88 void addline(int p, ll x, ll a, ll b)
89 {
90 if(t)
91 {
92 p = n - 1 - p, x = n - 1 - x;
93 b = (n - 1) * a + b; a = -a;
94 }
95
96 int &s = S[p], &e = E[p];
97
98 b -= V[p];
99
100 for(; s<=e; e--)
101 {
102 if(D[e].a == a && D[e].b < b) return;
103 if(D[e].a * D[e].x + D[e].b < a * D[e].x + b)
104 {
105 D[++e] = line((D[e].b - b) / (a - D[e].a) + 1, a, b);
106 return;
107 }
108 }
109
CAPITOLUL 3. IOI 2018 373
186
187 if(r != -1) DR.merge(m, r);
188 DR.addval(m, h * (m - s + 1));
189 DR.addline(m, e, h, (l != -1? DR.getval(l, m - 1) : 0) - h * (m-1));
190 if(l != -1) DR.merge(m, l);
191
192 return m;
193 }
194
195 vector <ll> minimum_costs(vector <int> _H, vector <int> _L,
196 vector <int> _R)
197 {
198 int i;
199
200 swap(H, _H);
201 swap(L, _L);
202 swap(R, _R);
203 n = H.size();
204 A.resize(L.size());
205
206 T.init(H);
207 DL.init(0, n);
208 DR.init(1, n);
209
210 for(i=0; i<L.size(); i++)
211 {
212 Q[T.getmax(L[i], R[i])].push_back(i);
213 }
214
215 dnc(0, n - 1);
216
217 return A;
218 }
219
220 //-------------- start grader ------------------
221
222 namespace
223 {
224 int read_int()
225 {
226 int x;
227 if (scanf("%d", &x) != 1)
228 {
229 fprintf(stderr, "Error while reading input\n");
230 exit(1);
231 }
232 return x;
233 }
234 } // namespace
235
236 int main()
237 {
238 std::freopen("../in/05-12.txt", "r", stdin);
239 std::freopen("meetings.out", "w", stdout);
240
241 auto t1 = clock();
242
243 int N = read_int();
244 int Q = read_int();
245 std::vector<int> H(N);
246 for (int i = 0; i < N; ++i)
247 {
248 H[i] = read_int();
249 }
250 std::vector<int> L(Q), R(Q);
251 for (int j = 0; j < Q; ++j)
252 {
253 L[j] = read_int();
254 R[j] = read_int();
255 }
256
257 fclose(stdin);
258 auto t2 = clock();
259
260 std::vector<long long> C = minimum_costs(H, L, R);
261
CAPITOLUL 3. IOI 2018 375
47
48 int get_sign(long long a)
49 {
50 return a<0 ? -1:a>0;
51 }
52
53 void add_line(lichao *tree, int n1, int n2,
54 int A, long long B, int bit=1, int s=0, int e=SZ-1)
55 {
56 int m=(s+e)>>1;
57 lazy_propagation(tree,bit,s,e);
58 if(n2<n1 || n2<s || e<n1) return;
59 if(n1<=s && e<=n2)
60 {
61 int &pA=tree[bit].A;
62 long long &pB=tree[bit].B, ys=1LL*A*s+B,
63 ym=1LL*A*m+B, ye=1LL*A*e+B,
64 pys=1LL*pA*s+pB, pym=1LL*pA*m+pB,
65 pye=1LL*pA*e+pB;
66 if(ym<pym)
67 {
68 swap(pA,A); swap(pB,B);
69 swap(pys,ys); swap(pym,ym); swap(pye,ye);
70 }
71
72 if(pys<=ys && pye<=ye) return;
73
74 if(get_sign(ys-pys)*get_sign(ym-pym)<0 || ym==pym && ys<pys)
75 add_line(tree,n1,n2,A,B,2*bit,s,m);
76 else
77 add_line(tree,n1,n2,A,B,2*bit+1,m+1,e);
78
79 return;
80 }
81
82 add_line(tree,n1,n2,A,B,2*bit,s,m);
83 add_line(tree,n1,n2,A,B,2*bit+1,m+1,e);
84 }
85
86 void add_tree(lichao *tree, int n1, int n2, long long v,
87 int bit=1, int s=0, int e=SZ-1)
88 {
89 int m=(s+e)>>1;
90 lazy_propagation(tree,bit,s,e);
91 if(n2<n1 || n2<s || e<n1) return;
92 if(n1<=s && e<=n2)
93 {
94 tree[bit].lazy=v;
95 lazy_propagation(tree,bit,s,e);
96 return;
97 }
98 add_tree(tree,n1,n2,v,2*bit,s,m);
99 add_tree(tree,n1,n2,v,2*bit+1,m+1,e);
100 }
101
102 long long get_y(lichao *tree, int x, int bit=1, int s=0, int e=SZ-1)
103 {
104 int m=(s+e)>>1;
105 lazy_propagation(tree,bit,s,e);
106 if(s==e) return 1LL*tree[bit].A*x+tree[bit].B;
107 return min(x<=m ? get_y(tree,x,2*bit,s,m):
108 get_y(tree,x,2*bit+1,m+1,e),1LL*tree[bit].A*x+tree[bit].B);
109 }
110
111 void solve(int s, int e)
112 {
113 if(s>e) return;
114 auto[M,m]=get_max(s,e);
115 solve(s,m-1);
116 solve(m+1,e);
117 for(auto[l,r,i]: Q[m])
118 res[i]=min(get_y(ltree,l)+(r-m+1LL)*M,get_y(rtree,r)+(m-l+1LL)*M);
119 add_tree(ltree,s,m-1,(e-m+1LL)*M);
120 add_line(ltree,s,m,-M,(m<e ? get_y(ltree,m+1):0)+M*(m+1LL));
121 add_tree(rtree,m+1,e,(m-s+1LL)*M);
122 add_line(rtree,m,e,M,(s<m ? get_y(rtree,m-1):0)+M*(1LL-m));
CAPITOLUL 3. IOI 2018 377
123 }
124
125 vector<long long> minimum_costs(vector<int> H,
126 vector<int> L, vector<int> R)
127 {
128 int N=H.size(), M=L.size();
129 res.resize(M);
130 for(int i=0;i<N;i++) Mtree[SZ+i+1]={H[i],i+1};
131 for(int i=SZ;--i;) Mtree[i]=max(Mtree[2*i],Mtree[2*i+1]);
132 for(int i=0;i<M;i++)
133 {
134 if(++L[i]<++R[i])
135 Q[get_max(L[i],R[i]).second].emplace_back(L[i],R[i],i);
136 else
137 res[i]=H[L[i]-1];
138 }
139
140 solve(1,N);
141 return res;
142 }
143
144 //-------------- start grader ------------------
145
146 namespace
147 {
148 int read_int()
149 {
150 int x;
151 if (scanf("%d", &x) != 1)
152 {
153 fprintf(stderr, "Error while reading input\n");
154 exit(1);
155 }
156 return x;
157 }
158 } // namespace
159
160 int main()
161 {
162 auto t1 = clock();
163
164 std::freopen("../in/05-12.txt", "r", stdin);
165 std::freopen("meetings.out", "w", stdout);
166
167 int N = read_int();
168 int Q = read_int();
169 std::vector<int> H(N);
170 for (int i = 0; i < N; ++i)
171 {
172 H[i] = read_int();
173 }
174 std::vector<int> L(Q), R(Q);
175 for (int j = 0; j < Q; ++j)
176 {
177 L[j] = read_int();
178 R[j] = read_int();
179 }
180
181 fclose(stdin);
182 auto t2 = clock();
183
184 std::vector<long long> C = minimum_costs(H, L, R);
185
186 auto t3 = clock();
187
188 for (size_t j = 0; j < C.size(); ++j)
189 {
190 printf("%lld\n", C[j]);
191 }
192
193 auto t4 = clock();
194
195 // reset console output
196 freopen("CON", "w", stdout);
197
198 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
CAPITOLUL 3. IOI 2018 378
199 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
200 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
201
202 return 0;
203 }
204 /*
205 t2-t1 = 1.109
206 t3-t2 = 11.448
207 t4-t3 = 0.75
208
209 Process returned 0 (0x0) execution time : 13.730 s
210 Press any key to continue.
211 */
https://cp-algorithms.com/geometry/convex_hull_trick.html
IOI 201727
4.1 Nowruz
Problema 1 - Nowruz 100 de puncte
Authors: Monika Steinová (Switzerland) and Michal Forisek (Slovakia)
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, ecare 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 ecare 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 ecare 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 ³iere de intrare, ecare
dintre ele descriind o gr din a bunicului. Pentru ecare ³ier de intrare trebuie s submitaµi un
³ier de ie³ire, care s conµin o hart a labirintului. Pentru ecare ³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 ³ier de intrare va descrie o matrice reprezentând gr dina ³i num rul de copii k invitaµi
de bunic. Formatul ³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
27
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).
379
CAPITOLUL 4. IOI 2017 380
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 e majuscul .)
CAPITOLUL 4. IOI 2017 381
Restricµii
a 1 & m, n & 1024
Punctaje
Fi³ierul output se consider a valid dac respect toate condiµiile urm toare:
a Harta de ie³ire va avea proprietatea de labirint, dup cum acesta a fost denit în enunµul
problemei.
Dac ³ierul output pentru un test nu va valid, scorul acordat pentru acest test va 0. în
caz contrar, scorul va 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 ind
num rul dat în ³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 ecare 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 a³at în CMS va '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 ecare 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 4. IOI 2017 382
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 4. IOI 2017 383
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.
8 #include <iostream>
9
10 #include <fstream>
11
12 using namespace std;
13
14 ifstream fin("../tests/02.in");
15 ofstream fout("02.out.txt");
16
17 #define rep(i, n) for (int i = 0, _n = (int)(n); i < _n; i++)
18 #define fer(i, x, n) for (int i = (int)(x), _n = (int)(n); i < _n; i++)
19 #define rof(i, n, x) for (int i = (int)(n), _x = (int)(x); i-- > _x; )
20 #define sz(x) (int((x).size()))
21 #define pb push_back
22 #define all(X) (X).begin(),(X).end()
23 #define X first
24 #define Y second
25 //#define endl ’\n’
26
27 template<class P, class Q> inline void smin(P &a, Q b) { if (b < a) a = b; }
28 template<class P, class Q> inline void smax(P &a, Q b) { if (a < b) a = b; }
29
30 typedef long long ll;
31 typedef pair<int, int> pii;
32
33 ////////////////////////////////////////////////////////////////////////////
34
35 struct solver
36 {
37 const int dx[4] = {0, -1, 0, 1};
38 const int dy[4] = {-1, 0, 1, 0};
39
40 static const int maxn = 2048 + 64;
41
42 static const char BLOCK = ’#’;
43 static const char OPEN = ’.’;
44 static const char TREE = ’X’;
45
46 int n, m;
47 string grid[maxn];
48
49 set<pair<int, pii>> s;
50
51 inline bool inside(pii p)
52 {
53 return 0 <= p.X && p.X < n && 0 <= p.Y && p.Y < m;
54 }
55
56 inline bool open(pii p)
57 {
58 return inside(p) && grid[p.X][p.Y] == OPEN;
59 }
60
61 inline pii adj(pii p, int d)
62 {
63 return pii(p.X + dx[d], p.Y + dy[d]);
64 }
65
66 int around(pii p, char ch)
67 { // counts number of ch’s around p
68 int cnt = 0;
69 rep(d, 4)
70 if(inside(adj(p, d)) && grid[p.X + dx[d]][p.Y + dy[d]] == ch)
71 cnt++;
72 else
73 if(!inside(adj(p, d)) && ch == BLOCK)
74 cnt++;
75 return cnt;
76 }
77
78 int extend(pii p, bool act)
79 { // act: determines whether to apply it or not
80 if(grid[p.X][p.Y] != OPEN || around(p, TREE) != 1)
81 return -1;
82
83 int cnt = 0;
CAPITOLUL 4. IOI 2017 385
236 }
237 }
238
239 rep(x, n)
240 if(!changed)
241 rep(y, m)
242 if(!changed && grid[x][y] == OPEN && around(pii(x, y), TREE) == 2)
243 {
244 vmark++; is_path = true;
245 int size = dfs(x, y);
246
247 int cnt = 0;
248 rep(dir, 4)
249 {
250 pii q = adj(pii(x, y), dir);
251 if(inside(q) &&
252 grid[q.X][q.Y] == TREE &&
253 around(q, TREE) == 1)
254 cnt++;
255 }
256
257 if((cnt == 2 && size < 7) || (size < 4)) continue;
258
259 rep(dir, 4)
260 {
261 pii q = adj(pii(x, y), dir);
262 if(inside(q) &&
263 grid[q.X][q.Y] == TREE &&
264 around(q, TREE) == 1)
265 {
266 grid[q.X][q.Y] = OPEN;
267 add(pii(x, y));
268 changed = true;
269 break;
270 }
271 }
272 }
273
274 if(!changed) break;
275 }
276 }
277
278 void read()
279 {
280 fin >> n >> m; // ***
281 int tmp;
282 fin >> tmp; // ***
283 rep(x, n) fin >> grid[x]; // ***
284 }
285
286 void write()
287 {
288 rep(x, n)
289 rep(y, m)
290 if(grid[x][y] == ’.’ || grid[x][y] == ’X’)
291 grid[x][y] ^= ’X’ ^ ’.’;
292
293 rep(x, n) cout << grid[x] << endl;
294 rep(x, n) fout << grid[x] << endl;
295 }
296 };
297
298 int main()
299 {
300 ios_base::sync_with_stdio(false);
301 fin.tie(0);
302
303 solver f;
304
305 f.read();
306 f.solve();
307 f.write();
308
309 return 0;
310 }
CAPITOLUL 4. IOI 2017 388
75 };
76
77 cout<<"argc = "<<argc<<"\n";
78 for(int kk=0;kk<argc;kk++)
79 cout<<argv[kk]<<"\n";
80 cout<<"----------------------\n";
81
82 registerChecker("nowruz", argc, argv);
83
84 m = inf.readInt();
85 inf.readSpace();
86
87 n = inf.readInt();
88 inf.readSpace();
89
90 answer = inf.readInt();
91 inf.readEoln();
92
93 // Read input and output mazes, and comparing if they match
94 for (int i = 0; i < m; i++)
95 {
96 string input = inf.readLine("[.#]{" + std::to_string(n) + "," +
97 std::to_string(n) + "}");
98 maze.push_back(ouf.readLine("[.#X]{" + std::to_string(n) + "," +
99 std::to_string(n) + "}"));
100 for (int j = 0; j < n; j++)
101 if (input[j] != maze[i][j] &&
102 (input[j] != ’.’ || maze[i][j] != ’X’))
103 quitf(_wa,
104 "Input and output maps are different at cell [%d, %d]",
105 i, j);
106 }
107
108 // Check if output maze is a tree, and count its leaves
109 int component = 0;
110 for (int i = 0; i < m; i++)
111 for (int j = 0; j < n; j++)
112 if (maze[i][j] == ’.’ && ! mark[i][j])
113 {
114 if (component++ > 0)
115 quitf(_wa, "Output maze is not connected");
116 BFS(i, j);
117 }
118
119 double score = int(leaves / (double)answer * 1000) / 1000.0;
120
121 if (abs(score) < 1e-5)
122 quitf(_wa, "Your rounded-down score is 0");
123
124 if (score < 1 - 1e-5)
125 quitp(score, "number of leaves: %d/%d", leaves, answer);
126
127 quitf(_ok, "number of leaves: %d/%d", leaves, answer);
128 }
129 /*
130 argc = 4
131 checker
132 ../tests/02.in
133 ../tests/02.out
134 02.out.txt
135 ----------------------
136 1
137 Correct
138 number of leaves: 1348/1338
139
140 Process returned 0 (0x0) execution time : 0.047 s
141 Press any key to continue.
142 */
28
OBS: Este folosit biblioteca testlib.h
2 #include <string>
3 #include <vector>
4
5 #include<ctime>
6
7 using namespace std;
8
9 vector <string> table;
10 int m, n, k;
11 int xplus[4] = {0, 1, 0, -1}, yplus[4] = {1, 0, -1, 0};
12
13 int cnt_neighbors(int x, int y)
14 {
15 int cnt = 0;
16 for (int i = 0; i < 4; i++)
17 if (table[x+xplus[i]][y+yplus[i]] == ’X’) cnt++;
18 return cnt;
19 }
20
21 bool addleaves(int x, int y)
22 {
23 bool found = false;
24 for (int i = 0; i < m; i++)
25 for (int j = 0; j < n; j++)
26 {
27 int a = 1 + (x + i) % m, b = 1 + (y + j) % n;
28 if (table[a][b] == ’.’ && cnt_neighbors(a, b) == 1)
29 {
30 table[a][b] = ’X’;
31 found = true;
32 }
33 }
34 return found;
35 }
36
37 int main()
38 {
39 auto t1 = clock();
40
41 // redirect console input to a file
42 std::freopen("../tests/07.in", "r", stdin) ;
43
44 // redirect console output to a file
45 std::freopen("07.out.txt", "w", stdout) ;
46
47 ios_base::sync_with_stdio(false); cin.tie(0);
48
49 cin >> m >> n >> k;
50 string s(n, ’#’);
51 table.push_back(s);
52 for (int i = 0; i < m; i++)
53 {
54 cin >> s;
55 table.push_back(’#’ + s + ’#’);
56 }
57 table.push_back(string(n, ’#’));
58
59 auto t2 = clock();
60
61 bool found = false;
62 for (int i = 2; i < m + 1 && ! found; i++)
63 for (int j = 2; j < n + 1 && ! found; j++)
64 if (table[i][j] == ’.’)
65 {
66 table[i][j] = ’X’;
67 addleaves(i, j);
68 found = true;
69 }
70
71 for(; addleaves(1,1););
72
73 for (int i = 1; i < m + 1; i++)
74 for (int j = 1; j < n + 1; j++)
75 if (table[i][j] == ’.’ || table[i][j] == ’X’)
76 table[i][j] = ’.’ + ’X’ - table[i][j];
77
CAPITOLUL 4. IOI 2017 391
78 auto t3 = clock();
79
80 for (int i = 1; i < m + 1; i++)
81 cout << table[i].substr(1, n) << endl;
82
83 auto t4 = clock();
84
85 // reset console output
86 freopen("CON", "w", stdout);
87
88 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
89 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
90 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
91
92 return 0;
93 }
94 /*
95 t2-t1 = 0
96 t3-t2 = 0.796
97 t4-t3 = 0
98
99 Process returned 0 (0x0) execution time : 0.844 s
100 Press any key to continue.
101
102 argc = 4
103 checker
104 ../tests/07.in
105 ../tests/07.out
106 07.out.txt
107 ----------------------
108 0.828
109 Partially Correct
110 number of leaves: 27639/33363
111
112 Process returned 0 (0x0) execution time : 0.203 s
113 Press any key to continue.
114 */
36
37 int main()
38 {
39 auto t1 = clock();
40
41 // redirect console input to a file
42 std::freopen("../tests/07.in", "r", stdin) ;
43
44 // redirect console output to a file
45 std::freopen("07.out.txt", "w", stdout) ;
46
47 ios_base::sync_with_stdio(false); cin.tie(0);
48
49 cin >> m >> n >> k;
50 string s(n, ’#’);
51 table.push_back(s);
52 for (int i = 0; i < m; i++) {
53 cin >> s;
54 table.push_back(’#’ + s + ’#’);
55 }
56 table.push_back(string(n, ’#’));
57
58 auto t2 = clock();
59
60 bool found = false;
61 for (int i = 2; i < m + 1 && ! found; i++)
62 for (int j = 2; j < n + 1 && ! found; j++)
63 if (table[i][j] == ’.’)
64 {
65 table[i][j] = ’X’;
66 addleaves(i, j);
67 found = true;
68 }
69
70 addleaves(0,0);
71
72 for (int i = 1; i < m + 1; i++)
73 for (int j = 1; j < n + 1; j++)
74 if (table[i][j] == ’.’ || table[i][j] == ’X’)
75 table[i][j] = ’.’ + ’X’ - table[i][j];
76
77 auto t3 = clock();
78
79 for (int i = 1; i < m + 1; i++)
80 cout << table[i].substr(1, n) << endl;
81
82 auto t4 = clock();
83
84 // reset console output
85 freopen("CON", "w", stdout);
86
87 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
88 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
89 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
90
91 return 0;
92 }
93 /*
94 t2-t1 = 0.015
95 t3-t2 = 0.047
96 t4-t3 = 0
97
98 Process returned 0 (0x0) execution time : 0.109 s
99 Press any key to continue.
100
101 argc = 4
102 checker
103 ../tests/07.in
104 ../tests/07.out
105 07.out.txt
106 ----------------------
107 0.080
108 Partially Correct
109 number of leaves: 2687/33363
110
111 Process returned 0 (0x0) execution time : 0.141 s
CAPITOLUL 4. IOI 2017 393
71 }
72
73 if (lnum != 2) return false;
74 table[x][y] = ’X’;
75 For(i, 4)
76 {
77 if (leaf[i])
78 {
79 table[x + xplus[i]][y+yplus[i]] = ’.’;
80 //cerr << "Tie found" << endl;
81 return true;
82 }
83 }
84 return false; // !!!
85 }
86
87 // dir = 0 : forward, 1: backward, 2: random
88 bool add_leaves(int x, int y, int dir)
89 {
90 bool found = false;
91 if (dir == 2)
92 {
93 for (int i = 0; i < m * n; i++)
94 allcells[i] = allcells[rand() % (i+1)];
95
96 for (int i = 0; i < m * n; i++)
97 found |= check_leaf(allcells[i].first, allcells[i].second);
98 }
99 else
100 For(i, m)
101 For(j, n)
102 {
103 int a = (dir) ? (m + x - i) % m : (i+x) % m;
104 int b = (dir) ? (n + y - j) % n : (j+y) % n;
105 found |= check_leaf(a, b);
106 }
107
108 if (! found)
109 for (int i = 1; i < m - 1; i++)
110 for (int j = 1; j < n - 1; j++)
111 found |= break_tie(i, j);
112
113 return found;
114 }
115
116 void try_add_leaves(int x, int y, bool random)
117 {
118 For(i, m)
119 For(j, n)
120 {
121 int a = (i + x) % m, b = (j + y) % n;
122 if (table[a][b] == ’.’)
123 {
124 table[a][b] = ’X’;
125 if (random) for (;add_leaves(0, 0, 2););
126 else for (int l = 0; add_leaves(a, b, l % 2); l++);
127 int cur_num = count_leaves();
128 if (cur_num > best_num)
129 {
130 best = table;
131 best_num = cur_num;
132 //cerr << best_num << endl;
133 }
134 table = first;
135 return;
136 }
137 }
138 }
139
140 int main()
141 {
142 auto t1 = clock();
143
144 // redirect console input to a file
145 std::freopen("../tests/07.in", "r", stdin) ;
146
CAPITOLUL 4. IOI 2017 395
4 #include <bitset>
5 #include <algorithm>
6
7 #include<ctime>
8
9 #define For(a, b) for (int a = 0; a < b; a++)
10 #define MAX (2048 + 64)
11 const int rplus[4] = {0,0,1,-1}, cplus[4] = {-1, 1, 0, 0};
12
13 using namespace std;
14
15 int m, n;
16 double leaf_prob = 0.2;
17 vector <string> table;
18 int counter;
19
20 void rand_perm(int* p)
21 {
22 for (int i = 0; i < 4; i++)
23 {
24 p[i] = i;
25 swap(p[i], p[rand() % (i + 1)]);
26 }
27 }
28
29 bool check2(int r, int c)
30 {
31 return (r < 0 || r >= m || c < 0 || c >= n || table[r][c] != ’X’);
32 }
33
34 bool check(int pr, int pc, int r, int c)
35 {
36 if (r < 0 || r >= m || c < 0 || c >= n || table[r][c] != ’.’)
37 return false;
38 For(i, 4)
39 if ((r + rplus[i] != pr || c + cplus[i] != pc) &&
40 ! check2(r + rplus[i], c + cplus[i]))
41 return false;
42 return true;
43 }
44
45 void DFS(int r, int c)
46 {
47 table[r][c] = ’X’;
48 if (counter++ > 10 && ((double) rand() / RAND_MAX) < leaf_prob)
49 return;
50 int p[4];
51 rand_perm(p);
52 For(i, 4)
53 if (check(r, c, r + rplus[p[i]], c + cplus[p[i]]))
54 DFS(r + rplus[p[i]], c + cplus[p[i]]);
55 }
56
57 bool inside(int a, int b)
58 {
59 return (a >= 0 && a < m && b >= 0 && b < n);
60 }
61
62 int neighbors(int x, int y)
63 {
64 int count = 0;
65 For(i, 4)
66 {
67 int a = x + rplus[i], b = y + cplus[i];
68 if (inside(a, b) && table[a][b] == ’X’) count ++;
69 }
70 return count;
71 }
72
73 void add_leaves() {
74 For(i, m)
75 For(j, n)
76 if (table[i][j] == ’.’ && neighbors(i, j) == 1) table[i][j] = ’X’;
77 }
78
79 int main(int argc, char ** argv)
CAPITOLUL 4. IOI 2017 397
80 {
81 auto t1 = clock();
82
83 // redirect console input to a file
84 std::freopen("../tests/07.in", "r", stdin) ;
85
86 // redirect console output to a file
87 std::freopen("07.out.txt", "w", stdout) ;
88
89 ios_base::sync_with_stdio(false); cin.tie(0);
90
91 // leaf_prob = atof(argv[1]);
92 // cerr << leaf_prob << endl;
93 cin >> m >> n;
94 int tmp; cin >> tmp;
95 string s;
96 int blocks = 0;
97 For(i, m)
98 {
99 cin >> s;
100 table.push_back(s);
101 blocks += count(s.begin(), s.end(), ’#’);
102 }
103
104 auto t2 = clock();
105
106 leaf_prob -= (double) blocks / (m * n);
107 bool found = false;
108 for (int i = 0; i < m && ! found; i++)
109 For(j, n)
110 if (table[i][j] == ’.’)
111 {
112 DFS(i, j);
113 found = true;
114 break;
115 }
116
117 add_leaves();
118 For(i, m)
119 For (j, n)
120 if (table[i][j] == ’.’ || table[i][j] == ’X’)
121 table[i][j] = ’.’ + ’X’ - table[i][j];
122
123 auto t3 = clock();
124
125 For (i, m)
126 cout << table[i] << endl;
127
128 auto t4 = clock();
129
130 // reset console output
131 freopen("CON", "w", stdout);
132
133 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
134 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
135 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
136
137 return 0;
138 }
139 /*
140 t2-t1 = 0.015
141 t3-t2 = 0.078
142 t4-t3 = 0
143
144 Process returned 0 (0x0) execution time : 0.141 s
145 Press any key to continue.
146
147 argc = 4
148 checker
149 ../tests/07.in
150 ../tests/07.out
151 07.out.txt
152 ----------------------
153 0.497
154 Partially Correct
155 number of leaves: 16602/33363
CAPITOLUL 4. IOI 2017 398
156
157 Process returned 0 (0x0) execution time : 0.188 s
158 Press any key to continue.
159 */
69
70 // reset console output
71 freopen("CON", "w", stdout);
72
73 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
74 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
75 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
76
77 return 0;
78 }
79 /*
80 t2-t1 = 0.015
81 t3-t2 = 0
82 t4-t3 = 0.016
83
84 Process returned 0 (0x0) execution time : 0.063 s
85 Press any key to continue.
86
87 argc = 4
88 checker
89 ../tests/07.in
90 ../tests/07.out
91 07.out.txt
92 ----------------------
93 0.001
94 Partially Correct
95 number of leaves: 47/33363
96
97 Process returned 0 (0x0) execution time : 0.141 s
98 Press any key to continue.
99 */
42
43 for(int i = 0; i <= n+1-1000+1000; i++)
44 {
45 for(int j = 0; j <= m+1-1000+1000; j++)
46 {
47 if(i==0||i==n+1-1000+1000||j==0||j==m+1-1000+1000)
48 grid[i][j] = ’#’;
49 if(grid[i][j] != ’#’)
50 grid[i][j] = ’X’;
51 }
52 }
53
54 for(int i = 0; i <= n+1; i++)
55 for(int j = 0; j <= m+1; j++)
56 grid2[i][j] = grid[i][j];
57
58 // for(int I = 1; I <= n; I++) {
59 // for(int J = 1; J <= m; J++) {
60 srand(time(NULL));
61 ll toDo = 200000000/((n*m));
62 ll totalToDo = toDo;
63 while((toDo-->0)&&bestScore<100)
64 {
65 ll I = (rand()%n) + 1;
66 ll J = (rand()%m) + 1;
67 for(int i = 0; i <= n+1; i++)
68 for(int j = 0; j <= m+1; j++)
69 grid[i][j] = grid2[i][j];
70 memset(visited, 0, sizeof(visited));
71 queue<pair<ll,ll>> q;
72 q.push({I, J});
73 while(!q.empty())
74 {
75 ll i = q.front().first;
76 ll j = q.front().second;
77 q.pop();
78
79 if(grid[i][j] == ’#’ || grid[i][j] == ’.’ ||
80 ((ll)(rand()*0.9))%(((max(n, m)*3)))==1)
81 continue;
82
83 if(visited[i+1][j ]+
84 visited[i-1][j ]+
85 visited[i ][j+1]+
86 visited[i ][j-1] > 1)
87 {
88 grid[i][j] = ’X’;
89 continue;
90 }
91 else
92 {
93 visited[i][j]=1;
94 grid[i][j]=’.’;
95 q.push({i+1, j });
96 q.push({i , j+1});
97 q.push({i-1, j });
98 q.push({i , j-1});
99 }
100 }
101
102 ll cnt = 0;
103 for(int i = 1; i <= n; i++)
104 {
105 for(int j = 1; j <= m; j++)
106 {
107 if(grid[i][j]==’.’ &&
108 visited[i ][j-1]+
109 visited[i-1][j ]+
110 visited[i+1][j ]+
111 visited[i ][j+1] == 1)
112 cnt++;
113 }
114 }
115
116 ld score = min((ld)100, 100*(ld)cnt/k);
117
CAPITOLUL 4. IOI 2017 401
118 if(score>bestScore)
119 {
120 bestScore = score;
121 for(int i = 0; i <= n+1; i++)
122 for(int j = 0; j <= m+1; j++)
123 bestGrid[i][j] = grid[i][j];
124 }
125
126 if((ll)(((ld)toDo/totalToDo*100))/10 >
127 (ll)(((ld)(toDo-1)/totalToDo*100))/10)
128 {
129 cerr << (ll)((ld)toDo/totalToDo*100) << "%: " << bestScore<<endl;
130 }
131
132 ll done = (((ld)I*m)+J)/(((ld)n*m)+m)*100;
133 //if((ll)lastDone/10<(ll)done/10)
134 lastDone = done;
135 }
136
137 for(int i = 1; i <= n; i++)
138 {
139 for(int j = 1; j <= m; j++)
140 {
141 fout << bestGrid[i][j];
142 }
143 fout << endl;
144 }
145 }
146 /*
147 64 64 1338
148 90%: 96.861
149 80%: 98.1315
150 70%: 98.1315
151 60%: 98.1315
152 50%: 98.3558
153 40%: 98.3558
154 30%: 98.3558
155 20%: 98.3558
156 10%: 98.3558
157
158 Process returned 0 (0x0) execution time : 257.489 s
159 Press any key to continue.
160
161 argc = 4
162 checker
163 ../tests/02.in
164 ../tests/02.out
165 02.out.txt
166 ----------------------
167 0.983
168 Partially Correct
169 number of leaves: 1316/1338
170
171 Process returned 0 (0x0) execution time : 1.931 s
172 Press any key to continue.
173 */
4.2 Wiring
Problema 2 - Wiring 100 de puncte
Author: Aleksandar IliÄ (Serbia)
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 folosit pentru a conecta oricare
CAPITOLUL 4. IOI 2017 402
dou puncte de conectare. Toate punctele de conetare pot 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 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 a³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 dierent O n or O n dp solutions for this subtask. The simplest one is
to dene dpi,j as the minimum cost needed for wiring the rst i red points and the rst 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 nd 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.
46 }
47 merge(tmp, tmp + nb, tmp + nb, tmp + nb + nr, p + 1);
48
49 int n = nb + nr;
50 int st = 1, lastSz = 0;
51 for(int i = 1; i <= n; i++)
52 {
53 if(p[i].color != p[i - 1].color)
54 {
55 for(int j = i; p[j].color == p[i].color; j++)
56 sum[i] += p[j].x;
57 for(int j = i - 1; j >= st; j--)
58 {
59 f[j] = -sum[j] + min(dp[j - 1], dp[j]) + 1LL * (i - j) * p[i - 1].x;
60 if(j < i - 1)
61 f[j] = min(f[j], f[j + 1]);
62 }
63 for(int j = st; j < i; j++)
64 {
65 g[j] = -sum[j] + min(dp[j - 1], dp[j]) + 1LL * (i - j) * p[i].x;
66 if(j > st)
67 g[j] = min(g[j], g[j - 1]);
68 }
69 lastSz = i - st;
70 st = i;
71 }
72 else
73 sum[i] = sum[i - 1] - p[i - 1].x;
74 if(st == 1)
75 {
76 dp[i] = 1e18;
77 continue;
78 }
79 int sz = i - st + 1;
80 long long curSum = sum[st] - sum[i] + p[i].x;
81 if(sz >= lastSz)
82 dp[i] = f[st - lastSz] + curSum - 1LL * sz * p[st - 1].x;
83 else
84 dp[i] = min(g[st - sz - 1] + curSum - 1LL * sz * p[st].x,
85 f[st - sz] + curSum - 1LL * sz * p[st - 1].x);
86 }
87 return dp[n];
88 }
89
90 int main()
91 {
92 auto t1 = clock();
93
94 std::freopen("../tests/5-29.in", "r", stdin) ;
95 std::freopen("wiring.out.txt", "w", stdout) ;
96
97 int n, m;
98 assert(2 == scanf("%d %d", &n, &m));
99
100 vector<int> r(n), b(m);
101 for(int i = 0; i < n; i++)
102 assert(1 == scanf("%d", &r[i]));
103 for(int i = 0; i < m; i++)
104 assert(1 == scanf("%d", &b[i]));
105
106 auto t2 = clock();
107
108 long long res = min_total_length(r, b);
109
110 auto t3 = clock();
111
112 printf("%lld\n", res);
113
114 auto t4 = clock();
115
116 // reset console output
117 freopen("CON", "w", stdout);
118
119 std::cout <<"res = "<<res<<’\n’<<’\n’;
120
121 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
CAPITOLUL 4. IOI 2017 407
122 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
123 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
124
125 return 0;
126 }
127 /*
128 res = 15991144105164
129
130 t2-t1 = 0.491
131 t3-t2 = 0.043
132 t4-t3 = 0
133
134 Process returned 0 (0x0) execution time : 0.582 s
135 Press any key to continue.
136 */
58 cnt[i] = cnt[i-1];
59 int j = head[i] - cnt[i];
60 if (cnt[i-1] == i - head[i])
61 if (j > head[j] && d[j-1] + val(j, i) > d[j-2] + val(j-1, i))
62 cnt[i]++, j--;
63 d[i] = min(d[j], d[j-1]) + val(j, i);
64 }
65 }
66
67 return d[n-1];
68 }
69
70 int main()
71 {
72 auto t1 = clock();
73
74 std::freopen("../tests/5-29.in", "r", stdin) ;
75 std::freopen("wiring.out.txt", "w", stdout) ;
76
77 int n, m;
78 assert(2 == scanf("%d %d", &n, &m));
79
80 vector<int> r(n), b(m);
81 for(int i = 0; i < n; i++)
82 assert(1 == scanf("%d", &r[i]));
83 for(int i = 0; i < m; i++)
84 assert(1 == scanf("%d", &b[i]));
85
86 auto t2 = clock();
87
88 long long res = min_total_length(r, b);
89
90 auto t3 = clock();
91
92 printf("%lld\n", res);
93
94 auto t4 = clock();
95
96 // reset console output
97 freopen("CON", "w", stdout);
98
99 std::cout <<"res = "<<res<<’\n’<<’\n’;
100
101 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
102 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
103 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
104
105 return 0;
106 }
107 /*
108 res = 15991144105164
109
110 t2-t1 = 0.493
111 t3-t2 = 0.307
112 t4-t3 = 0
113
114 Process returned 0 (0x0) execution time : 0.847 s
115 Press any key to continue.
116 */
90
91 std::freopen("../tests/5-29.in", "r", stdin) ;
92 std::freopen("wiring.out.txt", "w", stdout) ;
93
94 int n, m;
95 assert(2 == scanf("%d %d", &n, &m));
96
97 vector<int> r(n), b(m);
98 for(int i = 0; i < n; i++)
99 assert(1 == scanf("%d", &r[i]));
100 for(int i = 0; i < m; i++)
101 assert(1 == scanf("%d", &b[i]));
102
103 auto t2 = clock();
104
105 long long res = min_total_length(r, b);
106
107 auto t3 = clock();
108
109 printf("%lld\n", res);
110
111 auto t4 = clock();
112
113 // reset console output
114 freopen("CON", "w", stdout);
115
116 std::cout <<"res = "<<res<<’\n’<<’\n’;
117
118 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
119 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
120 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
121
122 return 0;
123 }
124 /*
125 res = 15991144105164
126
127 t2-t1 = 0.462
128 t3-t2 = 0.432
129 t4-t3 = 0
130
131 Process returned 0 (0x0) execution time : 0.950 s
132 Press any key to continue.
133 */
29 int nr = red.size();
30 for(int i = 0; i < nb; i++)
31 {
32 tmp[i].x = blue[i];
33 tmp[i].color = BLUE;
34 }
35
36 for(int i = 0; i < nr; i++)
37 {
38 tmp[nb + i].x = red[i];
39 tmp[nb + i].color = RED;
40 }
41
42 merge(tmp, tmp + nb, tmp + nb, tmp + nb + nr, p + 1);
43
44 int n = nb + nr;
45 int st = 1, lastSz = 0;
46 for(int i = 1; i <= n; i++)
47 {
48 if(p[i].color != p[i - 1].color)
49 {
50 for(int j = i; p[j].color == p[i].color; j++)
51 sum[i] += p[j].x;
52
53 for(int j = i - 1; j >= st; j--)
54 {
55 f[j] = -sum[j] + min(dp[j-1], dp[j]) + 1LL * (i-j) * p[i-1].x;
56 if(j < i - 1)
57 f[j] = min(f[j], f[j + 1]);
58 }
59
60 for(int j = st; j < i; j++)
61 {
62 g[j] = -sum[j] + min(dp[j-1], dp[j]) + 1LL * (i-j) * p[i].x;
63 if(j > st)
64 g[j] = min(g[j], g[j - 1]);
65 }
66
67 lastSz = i - st;
68 st = i;
69 }
70 else
71 sum[i] = sum[i - 1] - p[i - 1].x;
72
73 if(st == 1)
74 {
75 dp[i] = 1e18;
76 continue;
77 }
78
79 int sz = i - st + 1;
80 long long curSum = sum[st] - sum[i] + p[i].x;
81 if(sz >= lastSz)
82 dp[i] = f[st - lastSz] + curSum - 1LL * sz * p[st - 1].x;
83 else
84 dp[i] = min(g[st - sz - 1] + curSum - 1LL * sz * p[st].x,
85 f[st - sz] + curSum - 1LL * sz * p[st - 1].x);
86 }
87
88 return dp[n];
89 }
90
91 int main()
92 {
93 auto t1 = clock();
94
95 std::freopen("../tests/5-29.in", "r", stdin) ;
96 std::freopen("wiring.out.txt", "w", stdout) ;
97
98 int n, m;
99 assert(2 == scanf("%d %d", &n, &m));
100
101 vector<int> r(n), b(m);
102 for(int i = 0; i < n; i++)
103 assert(1 == scanf("%d", &r[i]));
104 for(int i = 0; i < m; i++)
CAPITOLUL 4. IOI 2017 412
40 sort(p, p+n);
41
42 rep(i, n) st[i] = (i == 0 || p[i].Y != p[i-1].Y ? i : st[i-1]);
43 rof(i, n, 0) ed[i] = (i == n-1 || p[i].Y != p[i+1].Y ? i+1 : ed[i+1]);
44
45 ps[0] = 0;
46 rep(i, n) ps[i+1] = ps[i] + p[i].X;
47
48 rep(i, n+1) dp[i][0] = dp[i][1] = infll;
49 dp[0][0] = 0;
50 fer(i, 1, n+1)
51 {
52 int s = st[i-1];
53 int e = ed[i-1];
54
55 if(s == i-1) smin(dp[i][0], dp[i-1][1]);
56 if(s != 0) {
57 smin(dp[i][0], dp[i-1][0] + p[i-1].X - p[s-1].X);
58 int len = i - s;
59 if(s - len >= 0)
60 smin(dp[i][0], dp[s-len][0]+(ps[i]-ps[s])-(ps[s]-ps[s-len]));
61 }
62 if(e != n) smin(dp[i][1], dp[i-1][0] + p[e].X - p[i-1].X);
63 smin(dp[i][0], dp[i][1]);
64 }
65
66 return dp[n][0];
67 }
68
69 int main()
70 {
71 auto t1 = clock();
72
73 std::freopen("../tests/5-29.in", "r", stdin) ;
74 std::freopen("wiring.out.txt", "w", stdout) ;
75
76 int n, m;
77 assert(2 == scanf("%d %d", &n, &m));
78
79 vector<int> r(n), b(m);
80 for(int i = 0; i < n; i++)
81 assert(1 == scanf("%d", &r[i]));
82 for(int i = 0; i < m; i++)
83 assert(1 == scanf("%d", &b[i]));
84
85 auto t2 = clock();
86
87 long long res = min_total_length(r, b);
88
89 auto t3 = clock();
90
91 printf("%lld\n", res);
92
93 auto t4 = clock();
94
95 // reset console output
96 freopen("CON", "w", stdout);
97
98 std::cout <<"res = "<<res<<’\n’<<’\n’;
99
100 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
101 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
102 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
103
104 return 0;
105 }
106 /*
107 res = 15991144105164
108
109 t2-t1 = 0.438
110 t3-t2 = 0.194
111 t4-t3 = 0
112
113 Process returned 0 (0x0) execution time : 0.682 s
114 Press any key to continue.
115 */
CAPITOLUL 4. IOI 2017 414
38 {
39 arr.pb(mp(b[bid],1));
40 bid++;
41 }
42 }
43 }
44
45 dp[0]=1e15;
46 prevv[0]=-1;
47 presum[0]=arr[0].first;
48
49 for (int i=1;i<n;i++)
50 {
51 presum[i]=presum[i-1]+arr[i].first;
52 dp[i]=1e15;
53 if (arr[i].second==arr[i-1].second)
54 prevv[i]=prevv[i-1];
55 else
56 prevv[i]=i-1;
57
58 for (int j=prevv[i-1]+1;j<=prevv[i];j++)
59 {
60 dp[j]=min(dp[j],dp[j-1]+arr[i].first-arr[j].first);
61 }
62
63 if (prevv[i]==-1) continue;
64
65 dp[i]=min(dp[i],dp[i-1]+arr[i].first-arr[prevv[i]].first);
66 if (prevv[prevv[i]]<=prevv[i]-(i-prevv[i]))
67 {
68 long long cur=presum[i]-presum[prevv[i]];
69 cur-=(presum[prevv[i]]-presum[prevv[i]-(i-prevv[i])]);
70 if (prevv[i]-(i-prevv[i])!=-1)
71 cur+=dp[prevv[i]-(i-prevv[i])];
72 dp[i]=min(dp[i],cur);
73 }
74 }
75
76 return dp[n-1];
77 }
78
79 int main()
80 {
81 auto t1 = clock();
82
83 std::freopen("../tests/5-29.in", "r", stdin) ;
84 std::freopen("wiring.out.txt", "w", stdout) ;
85
86 int n, m;
87 assert(2 == scanf("%d %d", &n, &m));
88
89 vector<int> r(n), b(m);
90 for(int i = 0; i < n; i++)
91 assert(1 == scanf("%d", &r[i]));
92 for(int i = 0; i < m; i++)
93 assert(1 == scanf("%d", &b[i]));
94
95 auto t2 = clock();
96
97 long long res = min_total_length(r, b);
98
99 auto t3 = clock();
100
101 printf("%lld\n", res);
102
103 auto t4 = clock();
104
105 // reset console output
106 freopen("CON", "w", stdout);
107
108 std::cout <<"res = "<<res<<’\n’<<’\n’;
109
110 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
111 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
112 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
113
CAPITOLUL 4. IOI 2017 417
114 return 0;
115 }
116 /*
117 res = 15991144105164
118
119 t2-t1 = 0.406
120 t3-t2 = 0.062
121 t4-t3 = 0
122
123 Process returned 0 (0x0) execution time : 0.500 s
124 Press any key to continue.
125 */
61 }
62 }
63
64 if(i + 1 < dp.size()) Minimize(dp[i + 1][0], dp[i].back());
65 else return dp[i].back();
66 }
67 return 0;
68 }
69
70 int main()
71 {
72 auto t1 = clock();
73
74 std::freopen("../tests/5-29.in", "r", stdin) ;
75 std::freopen("wiring.out.txt", "w", stdout) ;
76
77 int n, m;
78 assert(2 == scanf("%d %d", &n, &m));
79
80 vector<int> r(n), b(m);
81 for(int i = 0; i < n; i++)
82 assert(1 == scanf("%d", &r[i]));
83 for(int i = 0; i < m; i++)
84 assert(1 == scanf("%d", &b[i]));
85
86 auto t2 = clock();
87
88 long long res = min_total_length(r, b);
89
90 auto t3 = clock();
91
92 printf("%lld\n", res);
93
94 auto t4 = clock();
95
96 // reset console output
97 freopen("CON", "w", stdout);
98
99 std::cout <<"res = "<<res<<’\n’<<’\n’;
100
101 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
102 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
103 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
104
105 return 0;
106 }
107 /*
108 res = 15991144105164
109
110 t2-t1 = 0.391
111 t3-t2 = 0.5
112 t4-t3 = 0
113
114 Process returned 0 (0x0) execution time : 0.937 s
115 Press any key to continue.
116 */
44 }
45
46 vector<int> mirror(n, -1);
47 vector<llong> mirrorval(n);
48
49 for (int i = 1; i < n; ++i)
50 if (a[i] != a[i - 1])
51 for (int r = i, l = i - 1;
52 0 <= l && r < n && a[l] == a[i - 1] && a[r] == a[i];
53 --l, ++r)
54 {
55 mirror[r] = l;
56 mirrorval[r] = b[r] - b[l];
57 if (r > i)
58 mirrorval[r] += mirrorval[r - 1];
59 }
60
61 vector<llong> dp(n);
62 dp[0] = lone[0];
63
64 for (int i = 1; i < n; ++i)
65 {
66 dp[i] = dp[i - 1] + lone[i];
67 if (mirror[i] == -1) continue;
68 llong curdp = 0;
69 curdp += (mirror[i] ? dp[mirror[i] - 1] : 0);
70 curdp += mirrorval[i];
71 dp[i] = min(dp[i], curdp);
72 }
73
74 return dp[n - 1];
75 }
76
77 int main()
78 {
79 auto t1 = clock();
80
81 std::freopen("../tests/5-29.in", "r", stdin) ;
82 std::freopen("wiring.out.txt", "w", stdout) ;
83
84 int n, m;
85 assert(2 == scanf("%d %d", &n, &m));
86
87 vector<int> r(n), b(m);
88 for(int i = 0; i < n; i++)
89 assert(1 == scanf("%d", &r[i]));
90 for(int i = 0; i < m; i++)
91 assert(1 == scanf("%d", &b[i]));
92
93 auto t2 = clock();
94
95 long long res = min_total_length(r, b);
96
97 auto t3 = clock();
98
99 printf("%lld\n", res);
100
101 auto t4 = clock();
102
103 // reset console output
104 freopen("CON", "w", stdout);
105
106 std::cout <<"res = "<<res<<’\n’<<’\n’;
107
108 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
109 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
110 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
111
112 return 0;
113 }
114 /*
115 res = 15991144105164
116
117 t2-t1 = 0.39
118 t3-t2 = 0.453
119 t4-t3 = 0
CAPITOLUL 4. IOI 2017 422
120
121 Process returned 0 (0x0) execution time : 0.875 s
122 Press any key to continue.
123 */
145
146 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
147 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
148 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
149
150 return 0;
151 }
152 /*
153 res = 15991144105164
154
155 t2-t1 = 0.438
156 t3-t2 = 1.265
157 t4-t3 = 0
158
159 Process returned 0 (0x0) execution time : 1.828 s
160 Press any key to continue.
161 */
75
76 if(v2<=v1)
77 k++;
78 else
79 break;
80 }
81
82 dp[type][j] = pref - suf[k]
83 - max(0LL, (ll)j-k)*prev.back()
84 + max(0LL, (ll)k-j)*i[0]
85 + dp[!type][(int)prev.size()-k];
86 }
87
88 prev = i;
89 type ^= 1;
90 nr++;
91 }
92
93 return dp[!type][(int)prev.size()];
94 }
95
96 int main()
97 {
98 auto t1 = clock();
99
100 std::freopen("../tests/5-29.in", "r", stdin) ;
101 std::freopen("wiring.out.txt", "w", stdout) ;
102
103 int n, m;
104 assert(2 == scanf("%d %d", &n, &m));
105
106 vector<int> r(n), b(m);
107 for(int i = 0; i < n; i++)
108 assert(1 == scanf("%d", &r[i]));
109 for(int i = 0; i < m; i++)
110 assert(1 == scanf("%d", &b[i]));
111
112 auto t2 = clock();
113
114 long long res = min_total_length(r, b);
115
116 auto t3 = clock();
117
118 printf("%lld\n", res);
119
120 auto t4 = clock();
121
122 // reset console output
123 freopen("CON", "w", stdout);
124
125 std::cout <<"res = "<<res<<’\n’<<’\n’;
126
127 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
128 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
129 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
130
131 return 0;
132 }
133 /*
134 res = 15991144105164
135
136 t2-t1 = 0.422
137 t3-t2 = 0.516
138 t4-t3 = 0
139
140 Process returned 0 (0x0) execution time : 0.984 s
141 Press any key to continue.
142 */
CAPITOLUL 4. IOI 2017 428
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 ecare 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 a î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: ecare staµie este
deµinuta de Arezou sau de Borzou. Exist un singur tren. La începutul jocului trenul se a î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 ecare data c nd trenul intra într-o staµie pentru prima data, proprietarul acelei staµii
xeaz macazul din acea staµie.
Odat ce macazul a fost xat, 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 nit 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 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 iniµial in statia s. Se cere pentru ecare joc sa se ae 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 e 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 e 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 ) semnica 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 xeaz 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 xeaz 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 ecare 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 ecare 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 , dene 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 denition). We dene 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 satises one of the following conditions, we add v to set T .
CAPITOLUL 4. IOI 2017 430
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 denition, 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.
47 }
48
49 vector<int> who_wins(vector<int> a,vector<int> r,vector<int> u,vector<int> v)
50 {
51 int n = sz(a);
52 rep(i, sz(u)) radj[v[i]].pb(u[i]), deg[u[i]]++;
53 vector<int> res(n, 1);
54
55 for(bool cng = true; !(cng = !cng); )
56 {
57 rep(i, n)
58 need[i] = (a[i] ? 1 : deg[i]); // d only matters here
59
60 rep(i, n)
61 if(r[i] && res[i])
62 dfs(i, r); // dfs from yet-has-a-chance-to-win wells
63
64 rep(i, n)
65 if(r[i] && res[i] && need[i] > 0)
66 res[i] = false, cng = true; // and see if they had no chance
67 }
68
69 rep(i, n)
70 res[i] &= (need[i] <= 0); // look, more fopdoodles
71
72 return res;
73 }
74
75 int main() // grader ...
76 {
77 int n, m;
78 cinf >> n >> m; // ***
79
80 vector<int> a(n), r(n), u(m), v(m);
81
82 for(int i = 0; i < n; i++)
83 cinf >> a[i]; // ***
84
85 for(int i = 0; i < n; i++)
86 cinf >> r[i]; // ***
87
88 for(int i = 0; i < m; i++)
89 cinf >> u[i] >> v[i]; // ***
90
91 vector<int> res = who_wins(a, r, u, v);
92
93 for(int i = 0; i < (int)res.size(); i++)
94 printf(i ? " %d" : "%d", res[i]);
95 printf("\n");
96
97 return 0;
98 }
97
98 int n, m;
99 assert(2 == scanf("%d %d", &n, &m));
100
101 vector<int> a(n), r(n), u(m), v(m);
102
103 for(int i = 0; i < n; i++)
104 assert(1 == scanf("%d", &a[i]));
105
106 for(int i = 0; i < n; i++)
107 assert(1 == scanf("%d", &r[i]));
108
109 for(int i = 0; i < m; i++)
110 assert(2 == scanf("%d %d", &u[i], &v[i]));
111
112 auto t2 = clock();
113
114 vector<int> res = who_wins(a, r, u, v);
115
116 auto t3 = clock();
117
118 // BEGIN SECRET
119 printf("%s\n", output_secret.c_str());
120
121 if((int)res.size() != n)
122 {
123 printf("WA\n");
124 printf("Wrong returned array size\n");
125 }
126 else
127 printf("OK\n");
128 // END SECRET
129
130 for(int i = 0; i < (int)res.size(); i++)
131 printf(i ? " %d" : "%d", res[i]);
132 printf("\n");
133
134 auto t4 = clock();
135
136 // reset console output
137 freopen("CON", "w", stdout);
138
139 //std::cout <<"res = "<<res<<’\n’<<’\n’;
140
141 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
142 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
143 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
144
145 return 0;
146 }
147 /*
148 t2-t1 = 0.063
149 t3-t2 = 2.7
150 t4-t3 = 0
151
152 Process returned 0 (0x0) execution time : 2.857 s
153 Press any key to continue.
154 */
15 (char*)"checker",
16 (char*)"../tests/6-25.in", // input
17 (char*)"../tests/6-25.out", // rezultat corect
18 (char*)"train.out.txt", // rezultat de verificat si acordat punctaj
19 };
20
21 cout<<"argc = "<<argc<<"\n";
22 for(int kk=0;kk<argc;kk++)
23 cout<<argv[kk]<<"\n";
24 cout<<"----------------------\n";
25
26 registerChecker("train", argc, argv);
27
28 readBothSecrets(output_secret);
29 readBothGraderResults();
30
31 compareRemainingLines(3);
32 }
33 /*
34 argc = 4
35 checker
36 ../tests/6-25.in
37 ../tests/6-25.out
38 train.out.txt
39 ----------------------
40 1
41 Correct
42
43 Process returned 0 (0x0) execution time : 0.109 s
44 Press any key to continue.
45 */
42
43 vector<int> radj[maxn];
44 int deg[maxn], need[maxn];
45
46 void dfs(int u, vector<int> &w)
47 {
48 for(int v: radj[u])
49 {
50 need[v]--;
51 if(!w[v] && need[v] == 0)
52 dfs(v, w); // only dfs through non-charging vertices
53 }
54 }
55
56 vector<int> who_wins(vector<int> a, vector<int> r,
57 vector<int> u, vector<int> v)
58 {
59 int n = sz(a);
60 rep(i, sz(u)) radj[v[i]].pb(u[i]), deg[u[i]]++;
61 vector<int> res(n, 1);
62 for(bool cng = true; !(cng = !cng); )
63 {
64 rep(i, n)
65 need[i] = (a[i] ? 1 : deg[i]); // d only matters here
66 rep(i, n)
67 if(r[i] && res[i])
68 dfs(i, r); // dfs from yet-has-a-chance-to-win wells
69 rep(i, n)
70 if(r[i] && res[i] && need[i] > 0)
71 res[i] = false, cng = true; // and see if they had no chance
72 }
73
74 rep(i, n)
75 res[i] &= (need[i] <= 0); // look, more fopdoodles
76 return res;
77 }
78 // -----------------------------------------------------------
79 int main()
80 {
81 auto t1 = clock();
82
83 std::freopen("../tests/6-25.in", "r", stdin) ;
84 std::freopen("train.out.txt", "w", stdout) ;
85
86
87 // BEGIN SECRET
88 char secret[1000];
89 assert(1 == scanf("%s", secret));
90 if (string(secret) != input_secret)
91 {
92 printf("%s\n", output_secret.c_str());
93 printf("SV\n");
94 return 0;
95 }
96 // END SECRET
97
98 int n, m;
99 assert(2 == scanf("%d %d", &n, &m));
100
101 vector<int> a(n), r(n), u(m), v(m);
102
103 for(int i = 0; i < n; i++)
104 assert(1 == scanf("%d", &a[i]));
105
106 for(int i = 0; i < n; i++)
107 assert(1 == scanf("%d", &r[i]));
108
109 for(int i = 0; i < m; i++)
110 assert(2 == scanf("%d %d", &u[i], &v[i]));
111
112 auto t2 = clock();
113
114 vector<int> res = who_wins(a, r, u, v);
115
116 auto t3 = clock();
117
CAPITOLUL 4. IOI 2017 436
35 {
36 for (int i = 0; i < (int)u.size(); i++)
37 {
38 adj[u[i]].push_back(v[i]);
39 bak[v[i]].push_back(u[i]);
40 }
41
42 int n = (int)a.size();
43 for (int i = 0; i < n; i++)
44 f[i] = A;
45
46 while (true)
47 {
48 for (int i = 0; i < n; i++) if (f[i] != B)
49 {
50 mark[i] = false;
51 checked[i] = false;
52 need[i] = a[i] == A ? 1 : (int)adj[i].size();
53 }
54
55 queue<int> q;
56 for (int i = 0; i < n; i++) if (r[i] && f[i] == A)
57 q.push(i);
58
59 while (!q.empty())
60 {
61 int front = q.front();
62 q.pop();
63 if (checked[front] == true)
64 continue;
65 checked[front] = true;
66 for (int i = 0; i < (int)bak[front].size(); i++)
67 {
68 int temp = bak[front][i];
69 --need[temp];
70 if (need[temp] == 0 && mark[temp] == false && f[temp] == A)
71 {
72 q.push(temp);
73 mark[temp] = true;
74 }
75 }
76 }
77
78 bool flag = false;
79 for (int i = 0; i < n; i++) if (f[i] == A && mark[i] == false)
80 {
81 f[i] = B;
82 flag = true;
83 }
84
85 if (!flag)
86 break;
87 }
88
89 vector<int> res;
90 for (int i = 0; i < n; i++)
91 res.push_back(f[i]);
92
93 return res;
94 }
95 // -----------------------------------------------------------
96 int main()
97 {
98 auto t1 = clock();
99
100 std::freopen("../tests/6-25.in", "r", stdin) ;
101 std::freopen("train.out.txt", "w", stdout) ;
102
103
104 // BEGIN SECRET
105 char secret[1000];
106 assert(1 == scanf("%s", secret));
107 if (string(secret) != input_secret)
108 {
109 printf("%s\n", output_secret.c_str());
110 printf("SV\n");
CAPITOLUL 4. IOI 2017 438
111 return 0;
112 }
113 // END SECRET
114
115 int n, m;
116 assert(2 == scanf("%d %d", &n, &m));
117
118 vector<int> a(n), r(n), u(m), v(m);
119
120 for(int i = 0; i < n; i++)
121 assert(1 == scanf("%d", &a[i]));
122
123 for(int i = 0; i < n; i++)
124 assert(1 == scanf("%d", &r[i]));
125
126 for(int i = 0; i < m; i++)
127 assert(2 == scanf("%d %d", &u[i], &v[i]));
128
129 auto t2 = clock();
130
131 vector<int> res = who_wins(a, r, u, v);
132
133 auto t3 = clock();
134
135 // BEGIN SECRET
136 printf("%s\n", output_secret.c_str());
137
138 if((int)res.size() != n)
139 {
140 printf("WA\n");
141 printf("Wrong returned array size\n");
142 }
143 else
144 printf("OK\n");
145 // END SECRET
146
147 for(int i = 0; i < (int)res.size(); i++)
148 printf(i ? " %d" : "%d", res[i]);
149 printf("\n");
150
151 auto t4 = clock();
152
153 // reset console output
154 freopen("CON", "w", stdout);
155
156 //std::cout <<"res = "<<res<<’\n’<<’\n’;
157
158 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
159 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
160 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
161
162 return 0;
163 }
164 // -----------------------------------------------------------
165 /*
166 t2-t1 = 0.054
167 t3-t2 = 3.325
168 t4-t3 = 0
169
170 Process returned 0 (0x0) execution time : 3.456 s
171 Press any key to continue.
172 */
163
164 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
165 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
166 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
167
168 return 0;
169 }
170 // -----------------------------------------------------------
171 /*
172 t2-t1 = 0.078
173 t3-t2 = 5.147
174 t4-t3 = 0
175
176 Process returned 0 (0x0) execution time : 5.273 s
177 Press any key to continue.
178 */
1 // https://oj.uz/submission/160375
2
3 #include "train.h"
4 #include <bits/stdc++.h>
5
6 using namespace std;
7
8 // BEGIN SECRET
9 const string input_secret = "3d2051c242fe2ae63792f9868123a5eb";
10 const string output_secret = "d16905a4427c193ad87ae7fa91a2bb55";
11 // END SECRET
12
13 const int AREZOU = 1;
14 const int BORZOU = 0;
15 const int CHARGING_STATION = 1;
16 const int CHARGING_SET = 1;
17 const int VISITED = 1;
18
19 int N, M;
20 vector<int> station, owner;
21 vector<vector<int>> G, G_inverse;
22
23 vector<int> out_degree;
24 vector<int> visited;
25 vector<int> charging_set;
26 vector<int> new_charging_set;
27
28 void initialize_charging_set()
29 {
30 visited.assign(N, !VISITED);
31 out_degree.assign(N, 0);
32 charging_set.assign(N, !CHARGING_SET);
33
34 queue<int> q;
35 for (int i = 0; i < N; i++)
36 if (station[i] == CHARGING_STATION &&
37 new_charging_set[i] == CHARGING_SET)
38 q.push(i), visited[i] = VISITED;
39
40 while (!q.empty())
41 {
42 int u = q.front(); q.pop();
43 charging_set[u] = CHARGING_SET;
44 for (auto v : G_inverse[u])
45 {
46 if (visited[v] == VISITED) continue;
47
48 switch (owner[v])
49 {
50 case AREZOU:
51 if (visited[v] == !VISITED)
52 {
53 visited[v] = VISITED;
54 q.push(v);
55 }
56 break;
57 case BORZOU:
58 out_degree[v]++;
59 if (out_degree[v] == G[v].size() &&
60 visited[v] == !VISITED)
61 {
62 visited[v] = VISITED;
63 q.push(v);
64 }
65 break;
66 }
67 }
68 }
69
70 }
71
72 vector<int> who_wins(vector<int> owner_, vector<int> charge_,
73 vector<int> u_, vector<int> v_)
74 {
75 owner = owner_, station = charge_;
CAPITOLUL 4. IOI 2017 444
76 N = owner.size(), M = u_.size();
77 G.resize(N), G_inverse.resize(N);
78 new_charging_set.resize(N, CHARGING_SET);
79
80 for (int i = 0; i < M; i++)
81 {
82 G[u_[i]].push_back(v_[i]);
83 G_inverse[v_[i]].push_back(u_[i]);
84 }
85
86 while (charging_set != new_charging_set)
87 {
88 initialize_charging_set();
89
90 for (int i = 0; i < N; i++)
91 {
92 switch (owner[i])
93 {
94 case AREZOU:
95 new_charging_set[i] = !CHARGING_SET;
96 for (auto v : G[i])
97 if (charging_set[v] == CHARGING_SET)
98 new_charging_set[i] = CHARGING_SET;
99
100 break;
101
102 case BORZOU:
103 new_charging_set[i] = CHARGING_SET;
104 for (auto v : G[i])
105 if (charging_set[v] == !CHARGING_SET)
106 new_charging_set[i] = !CHARGING_SET;
107
108 break;
109 }
110 }
111
112 }
113
114 vector<int> res(N);
115 for (int i = 0; i < N; i++)
116 res[i] = (charging_set[i] == CHARGING_SET);
117
118 return res;
119 }
120 // -----------------------------------------------------------
121 int main()
122 {
123 auto t1 = clock();
124
125 std::freopen("../tests/6-25.in", "r", stdin) ;
126 std::freopen("train.out.txt", "w", stdout) ;
127
128
129 // BEGIN SECRET
130 char secret[1000];
131 assert(1 == scanf("%s", secret));
132 if (string(secret) != input_secret)
133 {
134 printf("%s\n", output_secret.c_str());
135 printf("SV\n");
136 return 0;
137 }
138 // END SECRET
139
140 int n, m;
141 assert(2 == scanf("%d %d", &n, &m));
142
143 vector<int> a(n), r(n), u(m), v(m);
144
145 for(int i = 0; i < n; i++)
146 assert(1 == scanf("%d", &a[i]));
147
148 for(int i = 0; i < n; i++)
149 assert(1 == scanf("%d", &r[i]));
150
151 for(int i = 0; i < m; i++)
CAPITOLUL 4. IOI 2017 445
27 tmp[i] = deg[i];
28 }
29
30 queue<int> q;
31
32 auto check = [&](int x)
33 {
34 if (!used[x])
35 {
36 if (a[x] == master)
37 {
38 used[x] = 1;
39 q.push(x);
40 }
41 else
42 if (--tmp[x] == 0)
43 {
44 used[x] = 1;
45 q.push(x);
46 }
47 }
48 };
49
50 for (int x : v)
51 {
52 used[x] = 1;
53 q.push(x);
54 }
55
56 while (!q.empty())
57 {
58 int node = q.front();
59 q.pop();
60
61 for (int to : g[node])
62 {
63 check(to);
64 }
65 }
66
67 vector<int> ans;
68 for (int i = 0; i < n; i++)
69 {
70 if (used[i])
71 ans.push_back(i);
72 }
73
74 return ans;
75 }
76
77 vector<int> who_wins(vector<int> a, vector<int> r,
78 vector<int> u, vector<int> v)
79 {
80 n = a.size(), m = u.size();
81
82 for (int i = 0; i < m; i++)
83 {
84 g[v[i]].push_back(u[i]);
85 deg[u[i]]++;
86 }
87
88 vector<int> res(n, 1);
89
90 bool work = true;
91
92 while (work)
93 {
94 work = false;
95
96 vector<int> sts;
97 for (int i = 0; i < n; i++)
98 {
99 if (r[i])
100 sts.push_back(i);
101 }
102
CAPITOLUL 4. IOI 2017 447
47 void removal()
48 {
49 for (int node : undet)
50 if (toRemove[node])
51 {
52 removing.emplace_back(node);
53 removed[node] = true;
54 }
55
56 while (!removing.empty())
57 {
58 int rm = removing.back();
59 removing.pop_back();
60
61 for (int next : graph[rm])
62 if (!removed[next])
63 {
64 currentDeg[next]--;
65 if (owner[next] == 1 || currentDeg[next] == 0)
66 {
67 removing.emplace_back(next);
68 removed[next] = true;
69 }
70 }
71 }
72 }
73
74 void findlosers()
75 {
76 reset();
77 for (int node : undet)
78 toRemove[node] = charge[node];
79 removal();
80
81 std::vector<int> losers;
82 for (int node : undet)
83 if (!removed[node])
84 losers.emplace_back(node);
85
86 reset();
87 flipowners();
88
89 for (int node : losers)
90 toRemove[node] = true;
91 removal();
92 flipowners();
93 }
94
95 std::vector<int> who_wins(std::vector<int> a, std::vector<int> r,
96 std::vector<int> u, std::vector<int> v)
97 {
98 int stations = a.size();
99 int tracks = u.size();
100
101 std::vector<int> winner(stations, 0);
102 for (int iNode = 0; iNode < stations; iNode++)
103 {
104 owner[iNode] = a[iNode];
105 charge[iNode] = r[iNode];
106 undet.emplace_back(iNode);
107 }
108
109 for (int iEdge = 0; iEdge < tracks; iEdge++)
110 {
111 graph[v[iEdge]].emplace_back(u[iEdge]);
112 degree[u[iEdge]]++;
113 }
114
115 while (!undet.empty())
116 {
117 findlosers();
118 std::vector<int> losers;
119
120 for (int node : undet)
121 if (removed[node])
122 losers.emplace_back(node);
CAPITOLUL 4. IOI 2017 450
123
124 if (losers.empty())
125 {
126 for (int node : undet)
127 winner[node] = 1;
128 undet.clear();
129 }
130 else
131 {
132 for (int node : losers)
133 {
134 for (int next : graph[node])
135 degree[next]--;
136 undet.erase(std::find(undet.begin(), undet.end(), node));
137 }
138 }
139 }
140
141 return winner;
142 }
143 // -----------------------------------------------------------
144 int main()
145 {
146 auto t1 = clock();
147
148 std::freopen("../tests/6-25.in", "r", stdin) ;
149 std::freopen("train.out.txt", "w", stdout) ;
150
151
152 // BEGIN SECRET
153 char secret[1000];
154 assert(1 == scanf("%s", secret));
155 if (string(secret) != input_secret)
156 {
157 printf("%s\n", output_secret.c_str());
158 printf("SV\n");
159 return 0;
160 }
161 // END SECRET
162
163 int n, m;
164 assert(2 == scanf("%d %d", &n, &m));
165
166 vector<int> a(n), r(n), u(m), v(m);
167
168 for(int i = 0; i < n; i++)
169 assert(1 == scanf("%d", &a[i]));
170
171 for(int i = 0; i < n; i++)
172 assert(1 == scanf("%d", &r[i]));
173
174 for(int i = 0; i < m; i++)
175 assert(2 == scanf("%d %d", &u[i], &v[i]));
176
177 auto t2 = clock();
178
179 vector<int> res = who_wins(a, r, u, v);
180
181 auto t3 = clock();
182
183 // BEGIN SECRET
184 printf("%s\n", output_secret.c_str());
185
186 if((int)res.size() != n)
187 {
188 printf("WA\n");
189 printf("Wrong returned array size\n");
190 }
191 else
192 printf("OK\n");
193 // END SECRET
194
195 for(int i = 0; i < (int)res.size(); i++)
196 printf(i ? " %d" : "%d", res[i]);
197 printf("\n");
198
CAPITOLUL 4. IOI 2017 451
51 {
52 memset(spas, 0, sizeof(spas));
53 memset(smrt, 0, sizeof(smrt));
54 memset(cnt, 0, sizeof(cnt));
55
56 for(int i = 0;i < n;i++)
57 {
58 if(izb[i]) continue;
59 if(rr[i] == 1) smrt[i] = 1, Q.push(i);
60 else
61 if(a[i] == 1) cnt[i] = 1;
62 else
63 {
64 cnt[i] = 0;
65 for(int x : v[i])
66 cnt[i] += !izb[x];
67 }
68 }
69
70 for(;!Q.empty();Q.pop())
71 {
72 int cur = Q.front();
73 for(int x : r[cur])
74 {
75 if(izb[x]) continue;
76 cnt[x]--;
77 if(cnt[x] == 0 && !smrt[x])
78 {
79 smrt[x] = 1;
80 Q.push(x);
81 }
82 }
83 }
84
85 for(int i = 0;i < n;i++)
86 {
87 if(izb[i]) continue;
88 if(smrt[i] == 0) spas[i] = 1, Q.push(i), cnt[i] = 0;
89 else
90 if(a[i] == 0) cnt[i] = 1;
91 else
92 {
93 cnt[i] = 0;
94 for(int x : v[i])
95 cnt[i] += !izb[x];
96 }
97 }
98
99 for(;!Q.empty();Q.pop())
100 {
101 int cur = Q.front();
102 for(int x : r[cur])
103 {
104 if(izb[x]) continue;
105 cnt[x]--;
106 if(cnt[x] == 0 && !spas[x])
107 {
108 spas[x] = 1;
109 Q.push(x);
110 }
111 }
112 }
113
114 int cc = 0;
115 for(int i = 0;i < n;i++)
116 if(spas[i] && !izb[i]) cc++, izb[i] = 1;
117 if(cc == 0) break;
118 }
119
120 vi sol;
121
122 for(int i = 0;i < n;i++)
123 sol.PB(!izb[i]);
124 return sol;
125 }
126 // -----------------------------------------------------------
CAPITOLUL 4. IOI 2017 453
203 */
72 DFS3(to);
73 }
74
75 vector<int> Solve3()
76 {
77 SCC();
78 vector<bool> goodcol(n);
79 for (int v = 0; v < n; ++v)
80 if (charge[v])
81 goodcol[col[v]] = true;
82 for (int v = 0; v < n; ++v)
83 if (goodcol[col[v]] && isCyc[col[v]] && !used3[v])
84 DFS3(v);
85 return vector<int>(ans, ans + n);
86 }
87
88 bool OK(vector<char>& mask)
89 {
90 queue<int> cycle;
91 for (int i = 0; i < n; ++i)
92 if (mask[i])
93 cycle.push(i);
94 int cnt = cycle.size();
95 while (cycle.size())
96 {
97 int u = cycle.front();
98 cycle.pop();
99 if (!mask[u]) continue;
100 bool g = false;
101
102 if (a[u])
103 {
104 g = true;
105 for (int to: nei[u])
106 if (!mask[to] && ans[to] != 0)
107 g = false;
108 }
109 else
110 {
111 g = false;
112 for (int to: nei[u])
113 if (mask[to] || ans[to] == 0)
114 g = true;
115 }
116
117 if (!g)
118 {
119 --cnt;
120 mask[u] = 0;
121 for (int to: rnei[u])
122 if (mask[to])
123 cycle.push(to);
124 }
125 }
126 return cnt;
127 }
128
129 void Add(vector<char>& mask)
130 {
131 queue<int> cycle;
132 for (int i = 0; i < n; ++i)
133 if (mask[i])
134 for (int to: rnei[i])
135 cycle.push(to);
136
137 while (cycle.size())
138 {
139 int u = cycle.front();
140 cycle.pop();
141 if (!ans[u]) continue;
142 bool g = false;
143 if (a[u])
144 {
145 g = true;
146 for (int to: nei[u])
147 if (ans[to] != 0)
CAPITOLUL 4. IOI 2017 456
148 g = false;
149 }
150 else
151 {
152 g = false;
153 for (int to: nei[u])
154 if (ans[to] == 0)
155 g = true;
156 }
157 if (g)
158 {
159 ans[u] = 0;
160 for (int to: rnei[u])
161 if (ans[to])
162 cycle.push(to);
163 }
164 }
165 }
166
167 vector<int> Solve()
168 {
169 for (int i = 0; i < n; ++i)
170 ans[i] = 1;
171
172 vector<char> stmask(n);
173
174 for (int i = 0; i < n; ++i)
175 if (!charge[i])
176 stmask[i] = 1;
177
178 while (true)
179 {
180 auto mask = stmask;
181 if (!OK(mask))
182 break;
183 for (int i = 0; i < n; ++i)
184 if (mask[i])
185 {
186 ans[i] = 0;
187 stmask[i] = 0;
188 }
189 Add(mask);
190 }
191
192 return vector<int>(ans, ans + n);
193 }
194
195 std::vector<int> who_wins(std::vector<int> a_, std::vector<int> charge_,
196 std::vector<int> u, std::vector<int> v)
197 {
198 n = a_.size();
199 for (int i = 0; i < n; ++i)
200 a[i] = a_[i], charge[i] = charge_[i];
201 for (int i = 0; i < u.size(); ++i)
202 nei[u[i]].push_back(v[i]);
203 for (int v = 0; v < n; ++v)
204 for (int to: nei[v])
205 rnei[to].push_back(v);
206 if (!count(a, a + n, 0))
207 return Solve3();
208 return Solve();
209 }
210 // -----------------------------------------------------------
211 int main()
212 {
213 auto t1 = clock();
214
215 std::freopen("../tests/6-25.in", "r", stdin) ;
216 std::freopen("train.out.txt", "w", stdout) ;
217
218 // BEGIN SECRET
219 char secret[1000];
220 assert(1 == scanf("%s", secret));
221 if (string(secret) != input_secret)
222 {
223 printf("%s\n", output_secret.c_str());
CAPITOLUL 4. IOI 2017 457
224 printf("SV\n");
225 return 0;
226 }
227 // END SECRET
228
229 int n, m;
230 assert(2 == scanf("%d %d", &n, &m));
231
232 vector<int> a(n), r(n), u(m), v(m);
233
234 for(int i = 0; i < n; i++)
235 assert(1 == scanf("%d", &a[i]));
236
237 for(int i = 0; i < n; i++)
238 assert(1 == scanf("%d", &r[i]));
239
240 for(int i = 0; i < m; i++)
241 assert(2 == scanf("%d %d", &u[i], &v[i]));
242
243 auto t2 = clock();
244
245 vector<int> res = who_wins(a, r, u, v);
246
247 auto t3 = clock();
248
249 // BEGIN SECRET
250 printf("%s\n", output_secret.c_str());
251
252 if((int)res.size() != n)
253 {
254 printf("WA\n");
255 printf("Wrong returned array size\n");
256 }
257 else
258 printf("OK\n");
259 // END SECRET
260
261 for(int i = 0; i < (int)res.size(); i++)
262 printf(i ? " %d" : "%d", res[i]);
263 printf("\n");
264
265 auto t4 = clock();
266
267 // reset console output
268 freopen("CON", "w", stdout);
269
270 //std::cout <<"res = "<<res<<’\n’<<’\n’;
271
272 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
273 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
274 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
275
276 return 0;
277 }
278 // -----------------------------------------------------------
279 /*
280 t2-t1 = 0.062
281 t3-t2 = 2.719
282 t4-t3 = 0
283
284 Process returned 0 (0x0) execution time : 2.828 s
285 Press any key to continue.
286 */
Jocul "Marele premiu" este un renumit show de televiziune. Sunteµi norocosul participant care
s-a calicat în runda nal . 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 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 ecare întrebare, veµi alege o cutie i. Ca r spuns, Rambod
v va oferi un ³ir a care conµine doi întregi. Semnicaµ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.
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 e î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)
Exemplul este ilustrat în gura de mai sus. Partea de sus arat valorile premiilor în ecare
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 ecare 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µ x 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 ecare 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 x 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 a³eaz o singur linie care conµine valoarea returnat de find_best ³i
num rul de apeluri a procedurii ask.
CAPITOLUL 4. IOI 2017 460
Subtask 1
In this subtask, We can nd the diamond with a simple binary search.
Subtask 2
First we query the rst 474 prize in the line. Itâs sucient to nd at least a lollipops
prize (cheapest). When we have found a lollipop, we can use binary search to nd 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 nding 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.
39
40 void bs(int l,int r,int nl,int nr)
41 {
42 if(l>r) return;
43 for(int i=0;i<=r-l;i++)
44 {
45 int mid,midl=(l+r)/2-i/2,midr=(l+r)/2+(i+1)/2;
46 if(i%2==0) mid=midl;
47 else mid=midr;
48 pii tmp=query(mid);
49 if(tmp.X+tmp.Y==numb)
50 {
51 int tmpl=(i%2==0?0:midr-midl);
52 int tmpr=(i%2==1?0:midr-midl);
53 if(tmp.X-tmpl>nl) bs(l,midl-1,nl,tmp.Y+tmpl);
54 if(tmp.Y-tmpr>nr) bs(midr+1,r,tmp.X+tmpr,nr);
55 break;
56 }
57 }
58 }
59
60 int find_best(int n)
61 {
62 if(n==1) return 0;
63 try{
64 numb=0;
65 memset(mark,false,sizeof mark);
66 int p=0;
67 for(int i=0;i<sqrt(n)+30 && i<n && numb<=26;i++)
68 {
69 pii tmp=query(i);
70 if(tmp.X+tmp.Y>numb) p=i;
71 numb=max(numb,tmp.X+tmp.Y);
72 }
73 bs(p,n-1,p,0);
74 }
75 catch(int ans){
76 return ans;
77 }
78 return -1;
79 }
80
81 // -------------------------------------------------
82 static const int max_q = 10000;
83 static int n;
84 static int query_count = 0;
85 static vector<int> g;
86 static vector<vector<int> > rank_count;
87
88 vector<int> ask(int i) {
89 query_count++;
90 if(query_count > max_q) {
91 cerr << "Query limit exceeded" << endl;
92 exit(0);
93 }
94
95 if(i < 0 || i >= n) {
96 cerr << "Bad index: " << i << endl;
97 exit(0);
98 }
99
100 vector<int> res(2);
101 res[0] = rank_count[g[i] - 1][i + 1];
102 res[1] = rank_count[g[i] - 1][n] - res[0];
103 return res;
104 }
105
106 int main()
107 {
108 cinf >> n; // ***
109
110 g.resize(n);
111 for(int i = 0; i < n; i++)
112 {
113 cinf >> g[i]; // ***
114 if(g[i] < 1) {
CAPITOLUL 4. IOI 2017 462
115 cerr << "Invalid rank " << g[i] << " at index " << i << endl;
116 exit(0);
117 }
118 }
119
120 int max_rank = *max_element(g.begin(), g.end());
121
122 rank_count.resize(max_rank + 1, vector<int>(n + 1, 0));
123 for(int r = 0; r <= max_rank; r++) {
124 for(int i = 1; i <= n; i++) {
125 rank_count[r][i] = rank_count[r][i - 1];
126 if(g[i - 1] == r)
127 rank_count[r][i]++;
128 }
129 }
130
131 for(int i = 0; i <= n; i++)
132 for(int r = 1; r <= max_rank; r++)
133 rank_count[r][i] += rank_count[r - 1][i];
134
135 int res = find_best(n);
136 cout << res << endl << "Query count: " << query_count << endl;
137
138 return 0;
139 }
48 int mid,midl=(l+r)/2-i/2,midr=(l+r)/2+(i+1)/2;
49 if(i%2==0) mid=midl;
50 else mid=midr;
51 pii tmp=query(mid);
52 if(tmp.X+tmp.Y==numb)
53 {
54 int tmpl=(i%2==0?0:midr-midl);
55 int tmpr=(i%2==1?0:midr-midl);
56 if(tmp.X-tmpl>nl) bs(l,midl-1,nl,tmp.Y+tmpl);
57 if(tmp.Y-tmpr>nr) bs(midr+1,r,tmp.X+tmpr,nr);
58 break;
59 }
60 }
61 }
62
63 int find_best(int n)
64 {
65 if(n==1) return 0;
66 try
67 {
68 numb=0;
69 memset(mark,false,sizeof mark);
70 int p=0;
71 for(int i=0;i<sqrt(n)+30 && i<n && numb<=26;i++)
72 {
73 pii tmp=query(i);
74 if(tmp.X+tmp.Y>numb) p=i;
75 numb=max(numb,tmp.X+tmp.Y);
76 }
77 bs(p,n-1,p,0);
78 }
79 catch(int ans)
80 {
81 return ans;
82 }
83 return -1;
84 }
85
86 // ---------- graderpublic -------------------
87
88 vector<int> ask(int i)
89 {
90 query_count++;
91 if(query_count > max_q)
92 {
93 cerr << "Query limit exceeded" << endl;
94 exit(0);
95 }
96
97 if(i < 0 || i >= n)
98 {
99 cerr << "Bad index: " << i << endl;
100 exit(0);
101 }
102
103 vector<int> res(2);
104 res[0] = rank_count[g[i] - 1][i + 1];
105 res[1] = rank_count[g[i] - 1][n] - res[0];
106 return res;
107 }
108
109 int main()
110 {
111 auto t1 = clock();
112
113 std::freopen("../tests/2-64.in", "r", stdin) ;
114 std::freopen("2-64.out.txt", "w", stdout) ;
115
116 string s;
117 getline (cin,s);
118 cout<<s<<"\n";
119
120 //cin >> n;
121 scanf("%d",&n);
122 //cout<<"n = "<<n<<"\n";
123
CAPITOLUL 4. IOI 2017 464
124 g.resize(n);
125 for(int i = 0; i < n; i++)
126 {
127 cin >> g[i];
128 if(g[i] < 1)
129 {
130 cerr << "Invalid rank " << g[i] << " at index " << i << endl;
131 exit(0);
132 }
133 }
134
135 auto t2 = clock();
136
137 int max_rank = *max_element(g.begin(), g.end());
138
139 rank_count.resize(max_rank + 1, vector<int>(n + 1, 0));
140 for(int r = 0; r <= max_rank; r++)
141 {
142 for(int i = 1; i <= n; i++)
143 {
144 rank_count[r][i] = rank_count[r][i - 1];
145 if(g[i - 1] == r)
146 rank_count[r][i]++;
147 }
148 }
149
150 for(int i = 0; i <= n; i++)
151 for(int r = 1; r <= max_rank; r++)
152 rank_count[r][i] += rank_count[r - 1][i];
153
154 int res = find_best(n);
155
156 auto t3 = clock();
157
158 cout << res << endl << "Query count: " << query_count << endl;
159
160 auto t4 = clock();
161
162 // reset console output
163 freopen("CON", "w", stdout);
164
165 std::cout <<"res = "<<res<< " Query count = " << query_count<<’\n’<<’\n’;
166
167 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
168 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
169 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
170
171 return 0;
172 }
173 /*
174 res = 111111 Query count = 555
175
176 t2-t1 = 0.244
177 t3-t2 = 0.082
178 t4-t3 = 0
179
180 Process returned 0 (0x0) execution time : 0.352 s
181 Press any key to continue.
182 */
14 static int n;
15 static int query_count = 0;
16 static vector<int> g;
17 static vector<vector<int> > rank_count;
18
19 // ----------- prize -------------------------
20 //#include "prize.h"
21 #include <bits/stdc++.h>
22
23 #define fi first
24 #define se second
25 #define ryan bear
26
27 //using namespace std;
28
29 typedef long long ll;
30 typedef pair<int,int> pii;
31 typedef pair<ll,ll> pll;
32 typedef long double ld;
33 typedef vector<int> vim;
34
35 int N;
36 set<pair<int, pii> > S[10];
37 int val[10], tp;
38
39 int ans, fl, chk[200010], ar[200010];
40
41 int f(int v)
42 {
43 for (int i=0; i<tp; i++) if (val[i]==v) return i;
44 val[tp]=v; return tp++;
45 }
46
47 void myfind(int s, int e)
48 {
49 if (s>e) return ;
50
51 int md=(s+e)/2;
52 if (chk[md]) return ;
53
54 chk[md]=1;
55 vim res=ask(md);
56 ar[md]=res[0]+res[1];
57 if (res[0]==0&&res[1]==0)
58 {
59 ans=md;
60 fl=1;
61 return ;
62 }
63
64 int ind=f(ar[md]);
65 S[ind].insert({md, make_pair(res[0], res[1])});
66
67 auto it=S[ind].find({md, make_pair(res[0], res[1])});
68 pair<int, pii> p=( *it), pr, ne;
69
70 if (it==S[ind].begin()) pr={-1, make_pair(0, ar[md])};
71 else pr=*prev(it);
72
73 if (next(it)==S[ind].end()) ne={N, make_pair(ar[md], 0)};
74 else ne=*next(it);
75
76 if (pr.se.fi!=p.se.fi) myfind(max(s, pr.fi+1), p.fi-1);
77 if (fl) return ;
78 if (p.se.fi!=ne.se.fi) myfind(p.fi+1, min(e, ne.fi-1));
79 }
80
81 int find_best(int n)
82 {
83 N=n;
84 myfind(0, n-1);
85 return ans;
86 }
87
88 // ---------- graderpublic -------------------
89
CAPITOLUL 4. IOI 2017 466
90 vector<int> ask(int i)
91 {
92 query_count++;
93 if(query_count > max_q)
94 {
95 cerr << "Query limit exceeded" << endl;
96 exit(0);
97 }
98
99 if(i < 0 || i >= n)
100 {
101 cerr << "Bad index: " << i << endl;
102 exit(0);
103 }
104
105 vector<int> res(2);
106 res[0] = rank_count[g[i] - 1][i + 1];
107 res[1] = rank_count[g[i] - 1][n] - res[0];
108 return res;
109 }
110
111 int main()
112 {
113 auto t1 = clock();
114
115 std::freopen("../tests/2-64.in", "r", stdin) ;
116 std::freopen("2-64.out.txt", "w", stdout) ;
117
118 string s;
119 getline (cin,s);
120 cout<<s<<"\n";
121
122 //cin >> n;
123 scanf("%d",&n);
124 //cout<<"n = "<<n<<"\n";
125
126 g.resize(n);
127 for(int i = 0; i < n; i++)
128 {
129 cin >> g[i];
130 if(g[i] < 1)
131 {
132 cerr << "Invalid rank " << g[i] << " at index " << i << endl;
133 exit(0);
134 }
135 }
136
137 auto t2 = clock();
138
139 int max_rank = *max_element(g.begin(), g.end());
140
141 rank_count.resize(max_rank + 1, vector<int>(n + 1, 0));
142 for(int r = 0; r <= max_rank; r++)
143 {
144 for(int i = 1; i <= n; i++)
145 {
146 rank_count[r][i] = rank_count[r][i - 1];
147 if(g[i - 1] == r)
148 rank_count[r][i]++;
149 }
150 }
151
152 for(int i = 0; i <= n; i++)
153 for(int r = 1; r <= max_rank; r++)
154 rank_count[r][i] += rank_count[r - 1][i];
155
156 int res = find_best(n);
157
158 auto t3 = clock();
159
160 cout << res << endl << "Query count: " << query_count << endl;
161
162 auto t4 = clock();
163
164 // reset console output
165 freopen("CON", "w", stdout);
CAPITOLUL 4. IOI 2017 467
166
167 std::cout <<"res = "<<res<< " Query count = " << query_count<<’\n’<<’\n’;
168
169 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
170 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
171 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
172
173 return 0;
174 }
175 /*
176 res = 111111 Query count = 85
177
178 t2-t1 = 0.258
179 t3-t2 = 0.071
180 t4-t3 = 0
181
182 Process returned 0 (0x0) execution time : 0.364 s
183 Press any key to continue.
184 */
130
131 string s;
132 getline (cin,s);
133 cout<<s<<"\n";
134
135 //cin >> n;
136 scanf("%d",&n);
137 //cout<<"n = "<<n<<"\n";
138
139 g.resize(n);
140 for(int i = 0; i < n; i++)
141 {
142 cin >> g[i];
143 if(g[i] < 1)
144 {
145 cerr << "Invalid rank " << g[i] << " at index " << i << endl;
146 exit(0);
147 }
148 }
149
150 auto t2 = clock();
151
152 int max_rank = *max_element(g.begin(), g.end());
153
154 rank_count.resize(max_rank + 1, vector<int>(n + 1, 0));
155 for(int r = 0; r <= max_rank; r++)
156 {
157 for(int i = 1; i <= n; i++)
158 {
159 rank_count[r][i] = rank_count[r][i - 1];
160 if(g[i - 1] == r)
161 rank_count[r][i]++;
162 }
163 }
164
165 for(int i = 0; i <= n; i++)
166 for(int r = 1; r <= max_rank; r++)
167 rank_count[r][i] += rank_count[r - 1][i];
168
169 int res = find_best(n);
170
171 auto t3 = clock();
172
173 cout << res << endl << "Query count: " << query_count << endl;
174
175 auto t4 = clock();
176
177 // reset console output
178 freopen("CON", "w", stdout);
179
180 std::cout <<"res = "<<res<< " Query count = " << query_count<<’\n’<<’\n’;
181
182 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
183 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
184 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
185
186 return 0;
187 }
188 /*
189 res = 111111 Query count = 324
190
191 t2-t1 = 0.253
192 t3-t2 = 0.074
193 t4-t3 = 0
194
195 Process returned 0 (0x0) execution time : 0.363 s
196 Press any key to continue.
197 */
5 #include <vector>
6 #include <algorithm>
7
8 #include<ctime>
9 #include <string>
10
11 using namespace std;
12
13 static const int max_q = 10000;
14 static int n;
15 static int query_count = 0;
16 static vector<int> g;
17 static vector<vector<int> > rank_count;
18
19 // ----------- prize -------------------------
20 //#include "prize.h"
21 //#include<vector>
22 #include<map>
23 #include<utility>
24 #include<cassert>
25
26 #define MAXN 200005
27
28 //using namespace std;
29
30 map<int, int> Q[MAXN];
31
32 int slv(int l, int r)
33 {
34 if (l > r) {return(-1);}
35 int mid = (l + r) >> 1;
36 vector<int> res = ask(mid);
37 int tot = res[0] + res[1], resL=-1, resR=-1;
38
39 if (tot == 0) {return(mid);}
40 else if (l == r) {return(-1);}
41
42 auto ptr1 = Q[tot].insert({mid, res[0]}).first, ptr2=ptr1;
43
44 if ((ptr1 == Q[tot].begin() || ( *(--ptr1)).second != res[0]) && res[0])
45 {
46 resL = slv(l, mid-1);
47 if (resL >= 0) {return(resL);}
48 }
49
50 if (((++ptr2) == Q[tot].end() || ( *ptr2).second != res[0]) && res[1])
51 {
52 resR = slv(mid+1, r);
53 if (resR >= 0) {return(resR);}
54 }
55 return(-1);
56 }
57
58 int find_best(int n)
59 {
60 return(slv(0, n-1));
61 }
62
63 // ---------- graderpublic -------------------
64
65 vector<int> ask(int i)
66 {
67 query_count++;
68 if(query_count > max_q)
69 {
70 cerr << "Query limit exceeded" << endl;
71 exit(0);
72 }
73
74 if(i < 0 || i >= n)
75 {
76 cerr << "Bad index: " << i << endl;
77 exit(0);
78 }
79
80 vector<int> res(2);
CAPITOLUL 4. IOI 2017 471
146 exit(0);
147 }
148
149 if(i < 0 || i >= n)
150 {
151 cerr << "Bad index: " << i << endl;
152 exit(0);
153 }
154
155 vector<int> res(2);
156 res[0] = rank_count[g[i] - 1][i + 1];
157 res[1] = rank_count[g[i] - 1][n] - res[0];
158 return res;
159 }
160
161 int main()
162 {
163 auto t1 = clock();
164
165 std::freopen("../tests/2-64.in", "r", stdin) ;
166 std::freopen("2-64.out.txt", "w", stdout) ;
167
168 string s;
169 getline (cin,s);
170 cout<<s<<"\n";
171
172 //cin >> n;
173 scanf("%d",&n);
174 //cout<<"n = "<<n<<"\n";
175
176 g.resize(n);
177 for(int i = 0; i < n; i++)
178 {
179 cin >> g[i];
180 if(g[i] < 1)
181 {
182 cerr << "Invalid rank " << g[i] << " at index " << i << endl;
183 exit(0);
184 }
185 }
186
187 auto t2 = clock();
188
189 int max_rank = *max_element(g.begin(), g.end());
190
191 rank_count.resize(max_rank + 1, vector<int>(n + 1, 0));
192 for(int r = 0; r <= max_rank; r++)
193 {
194 for(int i = 1; i <= n; i++)
195 {
196 rank_count[r][i] = rank_count[r][i - 1];
197 if(g[i - 1] == r)
198 rank_count[r][i]++;
199 }
200 }
201
202 for(int i = 0; i <= n; i++)
203 for(int r = 1; r <= max_rank; r++)
204 rank_count[r][i] += rank_count[r - 1][i];
205
206 int res = find_best(n);
207
208 auto t3 = clock();
209
210 cout << res << endl << "Query count: " << query_count << endl;
211
212 auto t4 = clock();
213
214 // reset console output
215 freopen("CON", "w", stdout);
216
217 std::cout <<"res = "<<res<< " Query count = " << query_count<<’\n’<<’\n’;
218
219 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
220 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
221 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
CAPITOLUL 4. IOI 2017 475
222
223 return 0;
224 }
225 /*
226 res = 111111 Query count = 624
227
228 t2-t1 = 0.247
229 t3-t2 = 0.071
230 t4-t3 = 0
231
232 Process returned 0 (0x0) execution time : 0.352 s
233 Press any key to continue.
234 */
60 vi svi;
61
62 void solve(int l,int r)
63 {
64 if(l > r) return;
65 if(get_L(l) + get_R(l) < loli)
66 {
67 svi.PB(l); solve(l + 1, r);
68 return;
69 }
70
71 if(l == r) return;
72 if(get_L(r) + get_R(r) < loli)
73 {
74 svi.PB(r);
75 solve(l, r - 1);
76 return;
77 }
78
79 if(get_L(l) == get_L(r) || l + 1 == r) return;
80 solve(l, (l + r) / 2);
81 solve((l + r) / 2, r);
82 }
83
84
85 int find_best(int n)
86 {
87 memset(L, -1, sizeof(L));
88 svi.clear();
89 loli = 0;
90 for(int i = 0;i < 100;i++)
91 {
92 int x = (rand() + rand()) % n;
93 x = (x % n + n) % n;
94 loli = max(loli, get_L(x) + get_R(x));
95 }
96
97 solve(0, n - 1);
98
99 for(int x : svi)
100 {
101 if(get_L(x) + get_R(x) == 0)
102 return x;
103 }
104
105 return 0;
106 }
107
108 // ---------- graderpublic -------------------
109
110 vector<int> ask(int i)
111 {
112 query_count++;
113 if(query_count > max_q)
114 {
115 cerr << "Query limit exceeded" << endl;
116 exit(0);
117 }
118
119 if(i < 0 || i >= n)
120 {
121 cerr << "Bad index: " << i << endl;
122 exit(0);
123 }
124
125 vector<int> res(2);
126 res[0] = rank_count[g[i] - 1][i + 1];
127 res[1] = rank_count[g[i] - 1][n] - res[0];
128 return res;
129 }
130
131 int main()
132 {
133 auto t1 = clock();
134
135 std::freopen("../tests/2-64.in", "r", stdin) ;
CAPITOLUL 4. IOI 2017 477
4 #include <iostream>
5 #include <vector>
6 #include <algorithm>
7
8 #include<ctime>
9 #include <string>
10
11 using namespace std;
12
13 static const int max_q = 10000;
14 static int n;
15 static int query_count = 0;
16 static vector<int> g;
17 static vector<vector<int> > rank_count;
18
19 // ----------- prize -------------------------
20
21 #include<bits/stdc++.h>
22
23 //#include "prize.h"
24 #define god dimasi5eks
25 #pragma GCC optimize("O3")
26 #define fi first
27 #define se second
28 #define pb push_back
29 #define pf push_front
30
31 // #define fisier 1
32
33 using namespace std;
34
35 typedef long long ll;
36
37 const int mod = 1000000007;
38 const double dancila = 3.14159265359; // PI
39 const double eps = 1e-9;
40
41 int ans;
42 map<int, pair<int, int> > m[200002];
43
44 pair<int, int> qu(int x)
45 {
46 vector<int> v = ask(x);
47 return {v[0], v[1]};
48 }
49
50 void solve(int st, int dr)
51 {
52 if(ans != -1 || st > dr)
53 return;
54
55 int mid = (st + dr) / 2;
56
57 pair<int, int> cur = qu(mid);
58 int sum = cur.fi + cur.se;
59
60 if(sum == 0)
61 {
62 ans = mid;
63 return;
64 }
65
66 auto it = m[sum].upper_bound(mid);
67 bool L = 1, R = 1;
68 if(it != m[sum].begin())
69 {
70 it--;
71 if(cur.se == it -> se.se)
72 L = 0;
73 it++;
74 }
75
76 if(it != m[sum].end())
77 {
78 if(cur.se == it -> se.se)
79 R = 0;
CAPITOLUL 4. IOI 2017 479
80 }
81
82 m[sum][mid] = cur;
83 if(L)
84 solve(st, mid - 1);
85 if(R)
86 solve(mid + 1, dr);
87 }
88
89 int find_best(int n)
90 {
91 ans = -1;
92 solve(0, n - 1);
93 return ans;
94 }
95
96 // ---------- graderpublic -------------------
97
98 vector<int> ask(int i)
99 {
100 query_count++;
101 if(query_count > max_q)
102 {
103 cerr << "Query limit exceeded" << endl;
104 exit(0);
105 }
106
107 if(i < 0 || i >= n)
108 {
109 cerr << "Bad index: " << i << endl;
110 exit(0);
111 }
112
113 vector<int> res(2);
114 res[0] = rank_count[g[i] - 1][i + 1];
115 res[1] = rank_count[g[i] - 1][n] - res[0];
116 return res;
117 }
118
119 int main()
120 {
121 auto t1 = clock();
122
123 std::freopen("../tests/2-64.in", "r", stdin) ;
124 std::freopen("2-64.out.txt", "w", stdout) ;
125
126 string s;
127 getline (cin,s);
128 cout<<s<<"\n";
129
130 //cin >> n;
131 scanf("%d",&n);
132 //cout<<"n = "<<n<<"\n";
133
134 g.resize(n);
135 for(int i = 0; i < n; i++)
136 {
137 cin >> g[i];
138 if(g[i] < 1)
139 {
140 cerr << "Invalid rank " << g[i] << " at index " << i << endl;
141 exit(0);
142 }
143 }
144
145 auto t2 = clock();
146
147 int max_rank = *max_element(g.begin(), g.end());
148
149 rank_count.resize(max_rank + 1, vector<int>(n + 1, 0));
150 for(int r = 0; r <= max_rank; r++)
151 {
152 for(int i = 1; i <= n; i++)
153 {
154 rank_count[r][i] = rank_count[r][i - 1];
155 if(g[i - 1] == r)
CAPITOLUL 4. IOI 2017 480
156 rank_count[r][i]++;
157 }
158 }
159
160 for(int i = 0; i <= n; i++)
161 for(int r = 1; r <= max_rank; r++)
162 rank_count[r][i] += rank_count[r - 1][i];
163
164 int res = find_best(n);
165
166 auto t3 = clock();
167
168 cout << res << endl << "Query count: " << query_count << endl;
169
170 auto t4 = clock();
171
172 // reset console output
173 freopen("CON", "w", stdout);
174
175 std::cout <<"res = "<<res<< " Query count = " << query_count<<’\n’<<’\n’;
176
177 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
178 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
179 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
180
181 return 0;
182 }
183 /*
184 res = 111111 Query count = 98
185
186 t2-t1 = 0.241
187 t3-t2 = 0.051
188 t4-t3 = 0
189
190 Process returned 0 (0x0) execution time : 0.348 s
191 Press any key to continue.
192 */
36 set<int> s[10000000];
37
38 ii q(int x)
39 {
40 if(used[x]) return mem[x];
41 used[x] = true;
42 vi a = ask(x);
43 mem[x] = ii(a[0],a[1]);
44 return mem[x];
45 }
46
47 int N;
48 int mina=0;
49 int rec(int l=0, int r=N-1)
50 {
51 if(l>r) return -1;
52 ii a = q(MID);
53 if(a.F+a.S==0) return MID;
54
55 int tot = a.F+a.S;
56 auto it = s[a.F+a.S].insert(MID).F;
57 if(it==s[tot].begin() || mem[ *prev(it) ] != mem[MID])
58 {
59 int b = rec(l,MID-1);
60 if(b!=-1) return b;
61 }
62
63 if(it==--s[tot].end() || mem[ *next(it) ] != mem[MID])
64 {
65 int b = rec(MID+1,r);
66 if(b!=-1) return b;
67 }
68 return -1;
69 }
70
71 int find_best(int n)
72 {
73 N = n;
74 int l=0, r=n-1;
75 int m;
76 int pos=0;
77 return rec();
78 }
79
80 // ---------- graderpublic -------------------
81
82 vector<int> ask(int i)
83 {
84 query_count++;
85 if(query_count > max_q)
86 {
87 cerr << "Query limit exceeded" << endl;
88 exit(0);
89 }
90
91 if(i < 0 || i >= n)
92 {
93 cerr << "Bad index: " << i << endl;
94 exit(0);
95 }
96
97 vector<int> res(2);
98 res[0] = rank_count[g[i] - 1][i + 1];
99 res[1] = rank_count[g[i] - 1][n] - res[0];
100 return res;
101 }
102
103 int main()
104 {
105 auto t1 = clock();
106
107 std::freopen("../tests/2-64.in", "r", stdin) ;
108 std::freopen("2-64.out.txt", "w", stdout) ;
109
110 string s;
111 getline (cin,s);
CAPITOLUL 4. IOI 2017 482
112 cout<<s<<"\n";
113
114 //cin >> n;
115 scanf("%d",&n);
116 //cout<<"n = "<<n<<"\n";
117
118 g.resize(n);
119 for(int i = 0; i < n; i++)
120 {
121 cin >> g[i];
122 if(g[i] < 1)
123 {
124 cerr << "Invalid rank " << g[i] << " at index " << i << endl;
125 exit(0);
126 }
127 }
128
129 auto t2 = clock();
130
131 int max_rank = *max_element(g.begin(), g.end());
132
133 rank_count.resize(max_rank + 1, vector<int>(n + 1, 0));
134 for(int r = 0; r <= max_rank; r++)
135 {
136 for(int i = 1; i <= n; i++)
137 {
138 rank_count[r][i] = rank_count[r][i - 1];
139 if(g[i - 1] == r)
140 rank_count[r][i]++;
141 }
142 }
143
144 for(int i = 0; i <= n; i++)
145 for(int r = 1; r <= max_rank; r++)
146 rank_count[r][i] += rank_count[r - 1][i];
147
148 int res = find_best(n);
149
150 auto t3 = clock();
151
152 cout << res << endl << "Query count: " << query_count << endl;
153
154 auto t4 = clock();
155
156 // reset console output
157 freopen("CON", "w", stdout);
158
159 std::cout <<"res = "<<res<< " Query count = " << query_count<<’\n’<<’\n’;
160
161 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
162 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
163 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
164
165 return 0;
166 }
167 /*
168 res = 111111 Query count = 98
169
170 t2-t1 = 0.239
171 t3-t2 = 0.073
172 t4-t3 = 0
173
174 Process returned 0 (0x0) execution time : 1.510 s
175 Press any key to continue.
176 */
CAPITOLUL 4. IOI 2017 483
4.5 Simurgh
Problema 5 - Simurgh 100 de puncte
Author: Saeed Seddighin (Iran)
O legend veche din Shahnameh spune c Zal, legendarul erou persan s-a îndr gostit de Ru-
bada, prinµesa de Kabul. Când Zal a cerut-o pe Rubada în c s torie, tat l ei i-a cerut s îndepli-
neasc 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 :
a pentru oricare pereche de ora³e, este posibil deplasarea din unul în cel lalt folosind doar
drumurile din acest set.
Mai mult, Zal poate adresa lui Simurgh unele întreb ri. Pentru ecare întrebare:
2. Simurgh îi spune lui Zal câte din drumurile setului selectat sunt drumuri regale.
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:
Restricµii ³i preciz ri
a 2 & n & 500
a n 1 & m & n n 1©2
a 0 & ui, v i & n 1 (pentru toate 0 & i & m 1)
a Pentru toate 0 & i & m 1, drumul i conecteaz dou ora³e distincte (ui j v i).
a Fiecare pereche de ora³e este conectat cu cel mult un drum.
a Cu ajutorul drumurilor date este posibil deplasarea între oricare dou ora³e.
a Setul compus din toate drumurile regale este un set de aur.
a find_roads trebuie s apeleze count_common_roads de cel mult q ori. în ecare apel,
setul de drumuri specicat de r trebuie s e un set de aur.
Subtask-uri
1. (13 puncte) n & 7, q = 30 000
2. (17 puncte) n & 50, q = 30 000
3. (21 puncte) n & 240, q = 30 000
4. (19 puncte) q = 12 000 ³i exist un drum între ecare pereche de ora³e
5. (30 puncte) q = 8 000
Evaluator local
Evaluatorul local cite³te datele din input în urm torul format:
a linia 1: n m
a linia 2 i (pentru toate 0 & i & m 1): ui v i
a linia 2 m: s0 s1 ... sn 2
Aici, 2 m: s0 s1 ... sn 2 sunt indicii drumurilor regale.
Evaluatorul local returneaz YES, dac find_roads apeleaz count_common_roads cel
mult 30 000 de ori, ³i returneaz setul corect de drumuri regale. în caz contrar, este returnat NO.
Atenµie! - procedura count_common_roads în evaluatorul local nu veric dac r posed
toate propriet µile unui set de aur. în schimb, ea num r ³i returneaz num rul de indici a
CAPITOLUL 4. IOI 2017 485
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
'Wrong Answer'.
Observaµie tehnic
Procedura count_common_roads în C++ ³i Pascal folose³te metoda pass by reference din
considerente de ecienµ . Puteµi apela procedura în modul obi³nuit. Se garanteaz c evaluatorul
nu va modica 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 nd 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 , nd 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 suces
to nd 2 other edges that make a triangle together with e and do as mentioned earlier. Fix an
arbitrary tree t and nd out which of its edges appear in Zal's tree. Once we nd 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 nd 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 dierence is that nding 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 nd an ear-decomposition for them. Note that for every cycle C we can gure
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 4. IOI 2017 486
71 vector<int> ANS;
72
73 inline void _renew()
74 {
75 vi __edges_new;
76 rep(i, __edges_vec) if(bit[i] && _last_id[i] != _next_)
77 __edges_new.pb(i), _last_id[i] = _next_;
78 ++ _next_;
79 __edges_vec = __edges_new;
80 }
81
82 inline int query()
83 {
84 _renew();
85 int res = count_common_roads(__edges_vec);
86 if(res == n-1)
87 ANS = __edges_vec;
88 return res;
89 }
90
91 inline void toggle(int i)
92 {
93 if(!bit[i])
94 {
95 bit[i] = true;
96 __edges_vec.pb(i);
97 }
98 else
99 bit[i] = false;
100 }
101
102 inline void reset()
103 {
104 while(!__edges_vec.empty())
105 {
106 int e = __edges_vec.back();
107 __edges_vec.PB;
108 bit[e] = false;
109 }
110 }
111
112 inline void dfs(int v = 0, int p = -1)
113 {
114 par[v] = p;
115 mark[v] = true;
116 highest[v] = {h[v], -1};
117 rep(u, adj[v])
118 {
119 int e = ind[v][u];
120 if(!mark[u])
121 {
122 h[u] = h[v] + 1;
123 dfs(u, v);
124 if(highest[v].x > highest[u].x)
125 highest[v] = highest[u];
126 }
127 else
128 if(highest[v].x > h[u] && u != p)
129 highest[v] = {h[u], e};
130 }
131
132 if(~p)
133 toggle(ind[v][p]);
134 }
135
136 inline void DFS(int v = 0)
137 {
138 int p = par[v];
139 rep(u, adj[v]) if(par[u] == v) DFS(u);
140 if(~p && state[v] == -1)
141 {
142 if(highest[v].x > h[p])
143 {
144 state[v] = 1;
145 return ;
146 }
CAPITOLUL 4. IOI 2017 488
147
148 int back_edge = highest[v].y;
149 int x = edges[back_edge].x, y = edges[back_edge].y;
150 if(h[x] > h[y]) swap(x, y);
151 int back_edge_num = query();
152 int mn = back_edge_num, mx = mn;
153 int cur = y;
154 int for_a_one = -1;
155 toggle(back_edge);
156
157 while(cur != x)
158 {
159 if(state[cur] == -1 or for_a_one == -1)
160 {
161 int cur_edge = ind[cur][par[cur]];
162 toggle(cur_edge);
163 last_num[cur_edge] = query();
164 sminmax(mn, mx, last_num[cur_edge]);
165 if(~state[cur])
166 for_a_one = last_num[cur_edge] - (!state[cur]);
167 toggle(cur_edge);
168 }
169 cur = par[cur];
170 }
171
172 toggle(back_edge);
173 cur = y;
174 while(cur != x)
175 {
176 if(state[cur] == -1)
177 {
178 int cur_edge = ind[cur][par[cur]];
179 if(~for_a_one)
180 state[cur] = last_num[cur_edge] == for_a_one;
181 else if(mn == mx)
182 state[cur] = 0;
183 else
184 state[cur] = last_num[cur_edge] == mn;
185 }
186
187 cur = par[cur];
188 }
189 }
190 }
191
192 vi tree, ans;
193
194 inline int root(int v)
195 {
196 return par[v] < 0? v: par[v] = root(par[v]);
197 }
198
199 inline bool merge(int ind)
200 {
201 int x = edges[ind].x, y = edges[ind].y;
202 x = root(x), y = root(y);
203 if(x == y) return false;
204 toggle(ind);
205 if(par[y] < par[x]) swap(x, y);
206 par[x] += par[y];
207 par[y] = x;
208 return true;
209 }
210
211 inline int edge_state(int i)
212 {
213 int x = edges[i].x, y = edges[i].y;
214 if(h[x] > h[y]) swap(x, y);
215 return state[y];
216 }
217
218 inline int query_for_forest(vi subset)
219 {
220 reset();
221 int sum = 0;
222 memset(par, -1, sizeof par);
CAPITOLUL 4. IOI 2017 489
34
35 int par[500];
36 int parEdge[500];
37 int dep[500];
38 int back[500];
39 int backEdge[500];
40 int ord = 0, base;
41
42 int royal[MAXM];
43 int sub[500];
44 int uf[500];
45
46 void dfs(int x, int p)
47 {
48 dep[x] = ++ord;
49 back[x] = dep[x];
50 backEdge[x] = -1;
51 for (road i : edge[x])
52 {
53 if (dep[i.x] != 0)
54 {
55 if (i.x != p && dep[i.x] < back[x])
56 {
57 back[x] = dep[i.x];
58 backEdge[x] = i.i;
59 }
60 continue;
61 }
62
63 dfsTree[i.i] = true;
64 dfsQ.push_back(i.i);
65 par[i.x] = x;
66 parEdge[i.x] = i.i;
67 dfs(i.x, x);
68
69 if (back[i.x] == dep[i.x])
70 royal[i.i] = 1;
71 else
72 if (back[i.x] < back[x])
73 {
74 back[x] = back[i.x];
75 backEdge[x] = backEdge[i.x];
76 }
77 }
78
79 if (back[x] < dep[x])
80 backGraph[backEdge[x]] = true;
81 }
82
83 int find(int x)
84 {
85 if (uf[x] != x) return uf[x] = find(uf[x]);
86 return x;
87 }
88
89 bool merge(int x, int y)
90 {
91 x = find(x);
92 y = find(y);
93 if (x == y) return false;
94 uf[x] = y;
95 return true;
96 }
97
98 int question(const vector<int> &vt)
99 {
100 vector<int> qs;
101 int other = 0;
102 for (int i = 0; i < n; ++i) uf[i] = i;
103 for (int i : vt)
104 {
105 qs.push_back(i);
106 merge(es[i].first, es[i].second);
107 }
108 for (int i : dfsQ)
109 {
CAPITOLUL 4. IOI 2017 493
186 else
187 allZero = false;
188 j = par[j];
189 }
190
191 vector<int> qs;
192 for (int k : dfsQ)
193 {
194 if (k != parEdge[j]) qs.push_back(k);
195 }
196
197 qs.push_back(i.second);
198 sub[j] = count_common_roads(qs) - base;
199 if (royal[parEdge[j]] != 0)
200 {
201 allZero = false;
202 royal[i.second] = royal[parEdge[j]] + 2 * sub[j];
203 }
204 else
205 if (sub[j] != 0)
206 {
207 allZero = false;
208 royal[parEdge[j]] = -sub[j];
209 royal[i.second] = sub[j];
210 }
211
212 if (allZero)
213 {
214 j = s;
215 while (j != e)
216 {
217 royal[parEdge[j]] = -1;
218 j = par[j];
219 }
220 royal[i.second] = -1;
221 continue;
222 }
223
224 j = s;
225 while (j != e)
226 {
227 if (royal[parEdge[j]] == 0)
228 royal[parEdge[j]] = royal[i.second] - 2 * sub[j];
229 j = par[j];
230 }
231 }
232
233 for (int i = 0; i < n; ++i)
234 {
235 vector<int> es;
236 for (road j : edge[i])
237 {
238 if (royal[j.i] == 0) es.push_back(j.i);
239 }
240 bsearch(es, 0, es.size() - 1, question(es));
241 }
242
243 vector<int> ret;
244 for (int i = 0; i < m; ++i)
245 {
246 if (royal[i] == 1) ret.push_back(i);
247 }
248
249 return ret;
250 }
251
252 // --------- graderpublic -------------------------
253
254 static int MAXQ = 30000;
255 int MAX_Q;
256
257 static int q = 0;
258 //static int n, m, q = 0;
259
260 static vector<int> u, v;
261 static vector<bool> goal;
CAPITOLUL 4. IOI 2017 495
262
263 static void wrong_answer()
264 {
265 printf("NO\n");
266 exit(0);
267 }
268
269 static bool is_valid(const vector<int>& r)
270 {
271 if(int(r.size()) != n - 1)
272 return false;
273
274 for(int i = 0; i < n - 1; i++)
275 if (r[i] < 0 || r[i] >= m)
276 return false;
277
278 return true;
279 }
280
281 static int _count_common_roads_internal(const vector<int>& r)
282 {
283 if(!is_valid(r))
284 wrong_answer();
285
286 int common = 0;
287 for(int i = 0; i < n - 1; i++)
288 {
289 bool is_common = goal[r[i]];
290 if (is_common)
291 common++;
292 }
293
294 return common;
295 }
296
297 int count_common_roads(const vector<int>& r)
298 {
299 q++;
300 if(q > MAX_Q)
301 // if(q > MAXQ)
302
303 wrong_answer();
304
305 return _count_common_roads_internal(r);
306 }
307
308 int main()
309 {
310 auto t1 = clock();
311
312 std::freopen("../tests/4-07.in", "r", stdin);
313 //std::freopen("4-07.out.txt", "w", stdout);
314
315 string s;
316 getline (cin,s);
317 cout<<s<<"\n";
318
319 assert(2 == scanf("%d %d", &n, &m));
320 cout<<"m="<<m<<" n="<<n<<"\n";
321
322 assert(1 == scanf("%d", &MAX_Q));
323 cout<<"MAX_Q = "<<MAX_Q<<"\n\n";
324
325 u.resize(m);
326 v.resize(m);
327
328 for(int i = 0; i < m; i++)
329 assert(2 == scanf("%d %d", &u[i], &v[i]));
330
331 goal.resize(m, false);
332
333 for(int i = 0; i < n - 1; i++)
334 {
335 int id;
336 assert(1 == scanf("%d", &id));
337 goal[id] = true;
CAPITOLUL 4. IOI 2017 496
338 }
339
340 auto t2 = clock();
341
342 vector<int> res = find_roads(n, u, v);
343
344 auto t3 = clock();
345
346 if(_count_common_roads_internal(res) != n - 1) wrong_answer();
347
348 //printf("YES\n");
349 printf("YES q = %d\n\n",q);
350
351 auto t4 = clock();
352
353 // reset console output
354 freopen("CON", "w", stdout);
355
356 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
357 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
358 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
359
360 return 0;
361 }
362 /*
363 wrslcnopzlckvxbnair_input_simurgh_lmncvpisadngpiqdfngslcnvd
364 m=124750 n=500
365 MAX_Q = 12000
366
367 YES q = 2536
368
369 t2-t1 = 0.406
370 t3-t2 = 0.39
371 t4-t3 = 0
372
373 Process returned 0 (0x0) execution time : 0.813 s
374 Press any key to continue.
375 */
171
172 int ret = count_common_roads(q);
173 return ret-cnt;
174 }
175
176 void solve(vector<int> &adj, int cnt = -1)
177 {
178 if (cnt == -1)
179 cnt = query_adj(adj);
180 if (cnt == 0)
181 {
182 for (auto e : adj)
183 ans[e] = 0;
184 return;
185 }
186
187 if (cnt == adj.size())
188 {
189 for (auto e : adj)
190 ans[e] = 1;
191 return;
192 }
193
194 int mid = adj.size()/2;
195 vector<int> L(adj.begin(), adj.begin()+mid);
196 vector<int> R(adj.begin()+mid, adj.end());
197
198 int lcnt = query_adj(L);
199 solve(L, lcnt);
200 solve(R, cnt-lcnt);
201 }
202
203 vector<int> find_roads(int _n, vector<int> _U, vector<int> _V)
204 {
205 // create adj list
206 n = _n;
207 U = _U, V = _V;
208 m = U.size();
209 for (int i = 0; i < m; ++i)
210 {
211 int u = U[i], v = V[i];
212 G[u].emplace_back(v, i);
213 G[v].emplace_back(u, i);
214 }
215
216 // build dfs tree and find answer for the tree
217 fill(ans, ans+m, -1);
218 dfs(0, -1);
219 defcnt = count_common_roads(T);
220 for (int i = 0; i < n; ++i)
221 {
222 if (low[i].S != -1)
223 query_cycle(low[i].S);
224 }
225
226 // find answer for each node
227 for (int u = 0; u < n; ++u)
228 {
229 vector<int> adj;
230 for (auto v : G[u])
231 {
232 if (ans[v.S] == -1)
233 adj.push_back(v.S);
234 }
235 solve(adj);
236 }
237
238 // return answer
239 vector<int> ret;
240 for (int i = 0; i < m; ++i)
241 {
242 if (ans[i])
243 ret.push_back(i);
244 }
245 return ret;
246 }
CAPITOLUL 4. IOI 2017 504
247
248 // --------- graderpublic -------------------------
249
250 static int MAXQ = 30000;
251 int MAX_Q;
252
253 static int q = 0;
254 //static int n, m, q = 0;
255
256 static vector<int> u, v;
257 static vector<bool> goal;
258
259 static void wrong_answer()
260 {
261 printf("NO\n");
262 exit(0);
263 }
264
265 static bool is_valid(const vector<int>& r)
266 {
267 if(int(r.size()) != n - 1)
268 return false;
269
270 for(int i = 0; i < n - 1; i++)
271 if (r[i] < 0 || r[i] >= m)
272 return false;
273
274 return true;
275 }
276
277 static int _count_common_roads_internal(const vector<int>& r)
278 {
279 if(!is_valid(r))
280 wrong_answer();
281
282 int common = 0;
283 for(int i = 0; i < n - 1; i++)
284 {
285 bool is_common = goal[r[i]];
286 if (is_common)
287 common++;
288 }
289
290 return common;
291 }
292
293 int count_common_roads(const vector<int>& r)
294 {
295 q++;
296 if(q > MAX_Q)
297 // if(q > MAXQ)
298
299 wrong_answer();
300
301 return _count_common_roads_internal(r);
302 }
303
304 int main()
305 {
306 auto t1 = clock();
307
308 std::freopen("../tests/4-07.in", "r", stdin);
309 //std::freopen("4-07.out.txt", "w", stdout);
310
311 string s;
312 getline (cin,s);
313 cout<<s<<"\n";
314
315 assert(2 == scanf("%d %d", &n, &m));
316 cout<<"m="<<m<<" n="<<n<<"\n";
317
318 assert(1 == scanf("%d", &MAX_Q));
319 cout<<"MAX_Q = "<<MAX_Q<<"\n\n";
320
321 u.resize(m);
322 v.resize(m);
CAPITOLUL 4. IOI 2017 505
323
324 for(int i = 0; i < m; i++)
325 assert(2 == scanf("%d %d", &u[i], &v[i]));
326
327 goal.resize(m, false);
328
329 for(int i = 0; i < n - 1; i++)
330 {
331 int id;
332 assert(1 == scanf("%d", &id));
333 goal[id] = true;
334 }
335
336 auto t2 = clock();
337
338 vector<int> res = find_roads(n, u, v);
339
340 auto t3 = clock();
341
342 if(_count_common_roads_internal(res) != n - 1) wrong_answer();
343
344 //printf("YES\n");
345 printf("YES q = %d\n\n",q);
346
347 auto t4 = clock();
348
349 // reset console output
350 freopen("CON", "w", stdout);
351
352 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
353 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
354 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
355
356 return 0;
357 }
358 /*
359 wrslcnopzlckvxbnair_input_simurgh_lmncvpisadngpiqdfngslcnvd
360 m=124750 n=500
361 MAX_Q = 12000
362
363 YES q = 2541
364
365 t2-t1 = 0.343
366 t3-t2 = 0.422
367 t4-t3 = 0.016
368
369 Process returned 0 (0x0) execution time : 0.797 s
370 Press any key to continue.
371 */
24
25 int type[505],dep[505],deg[505],boss[505],n;
26 set<int> s;
27 bitset<505> vis,ed;
28 bitset<250000> used;
29
30 int ccr()
31 {
32 return count_common_roads(vector<int>(s.begin(),s.end()));
33 }
34
35 void dfs(int u,int f,int num,int d)
36 {
37 pa[u]=MP(f,num),dep[u]=d,vis[u]=1;
38 if(~num) used[num]=1,s.insert(num);
39 for(pii i:G[u])
40 if(!vis[i.F])
41 dfs(i.F,u,i.S,d+1);
42 }
43
44 int finds(int x)
45 {
46 if(x==boss[x]) return x;
47 return boss[x]=finds(boss[x]);
48 }
49
50 int Union(int a,int b)
51 {
52 a=finds(a),b=finds(b);
53 if(a==b) return 0;
54 return boss[a]=b,1;
55 }
56
57 int ccr_forest(vector<int> f)
58 {
59 int cnt=0;
60 for(int i=0;i<n;++i)
61 boss[i]=i;
62
63 set<int> tmp;
64 for(int i:f)
65 tmp.insert(i),Union(U[i],V[i]);
66 for(int i=1;i<n;++i)
67 if(Union(i,pa[i].F))
68 cnt+=type[i],tmp.insert(pa[i].S);
69 tmp.swap(s),cnt=ccr()-cnt,tmp.swap(s);
70
71 return cnt;
72 }
73
74 int leaf_finding(int u)
75 {
76 vector<int> candi;
77 for(pii i:G[u])
78 if(!ed[i.F])
79 candi.pb(i.S);
80
81 int l=0,r=candi.size()-1;
82 while(l<r)
83 {
84 vector<int> v;
85 int m=l+r>>1;
86 for(int i=l;i<=m;++i)
87 v.pb(candi[i]);
88 if(ccr_forest(v)>=1) r=m;
89 else l=m+1;
90 }
91 return candi[l];
92 }
93
94 vector<int> find_roads(int N, vector<int> u, vector<int> v)
95 {
96 n=N,U=u,V=v;
97 vector<int> ans;
98 for(int i=0;i<u.size();++i)
99 G[u[i]].pb(MP(v[i],i)),G[v[i]].pb(MP(u[i],i));
CAPITOLUL 4. IOI 2017 507
100
101 dfs(0,-1,-1,0),fill(type,type+N,-1);
102
103 int cur=ccr();
104 for(int i=0;i<u.size();++i)
105 {
106 if(used[i]) continue;
107 int cnt=0,sz=0,tp=-1,a=u[i],b=v[i];
108 pii sw;
109 while(a!=b)
110 {
111 if(dep[a]<dep[b]) swap(a,b);
112 if(~type[a]) sw=MP(pa[a].S,type[a]);
113 cnt+=!~type[a],++sz,a=pa[a].F;
114 }
115 if(!cnt) continue;
116 a=u[i],b=v[i];
117 if(cnt==sz)
118 {
119 vector<int> v;
120 while(a!=b)
121 {
122 if(dep[a]<dep[b]) swap(a,b);
123 s.erase(pa[a].S),s.insert(i);
124 int tmp=ccr();
125 if(tmp==cur) v.pb(a);
126 else
127 {
128 if(tmp>cur) tp=1,type[a]=0;
129 else tp=0,type[a]=1;
130 for(int j:v)
131 type[j]=tp;
132 s.erase(i),s.insert(pa[a].S),a=pa[a].F;
133 break;
134 }
135 s.erase(i),s.insert(pa[a].S),a=pa[a].F;
136 }
137 if(a==b&&!~tp)
138 for(int j:v)
139 type[j]=0;
140 }
141 else
142 s.erase(sw.F),
143 s.insert(i),
144 tp=(sw.S==0)^(ccr()==cur),
145 s.erase(i),
146 s.insert(sw.F);
147
148 while(a!=b)
149 {
150 if(dep[a]<dep[b]) swap(a,b);
151 s.erase(pa[a].S),s.insert(i);
152 if(!~type[a])
153 type[a]=tp^(ccr()!=cur);
154 s.erase(i),s.insert(pa[a].S),a=pa[a].F;
155 }
156 }
157
158 for(int i=1;i<n;++i)
159 if(!~type[i]) type[i]=1;
160
161 for(int i=0;i<n;++i)
162 {
163 vector<int> v;
164 for(pii j:G[i])
165 v.pb(j.S);
166 deg[i]=ccr_forest(v);
167 if(deg[i]==1)
168 q.push(i);
169 }
170
171 while(q.size()>1)
172 {
173 int u=q.front();
174 q.pop(),
175 ed[u]=1,
CAPITOLUL 4. IOI 2017 508
176 ans.pb(leaf_finding(u)),
177 u^=U[ans.back()]^V[ans.back()];
178 if(--deg[u]==1)
179 q.push(u);
180 }
181 return ans;
182 }
183
184 // --------- graderpublic -------------------------
185
186 static int MAXQ = 30000;
187 int MAX_Q;
188
189 static int m,qq = 0;
190 //static int n, m, q = 0;
191
192 static vector<int> u, v;
193 static vector<bool> goal;
194
195 static void wrong_answer()
196 {
197 printf("NO\n");
198 exit(0);
199 }
200
201 static bool is_valid(const vector<int>& r)
202 {
203 if(int(r.size()) != n - 1)
204 return false;
205
206 for(int i = 0; i < n - 1; i++)
207 if (r[i] < 0 || r[i] >= m)
208 return false;
209
210 return true;
211 }
212
213 static int _count_common_roads_internal(const vector<int>& r)
214 {
215 if(!is_valid(r))
216 wrong_answer();
217
218 int common = 0;
219 for(int i = 0; i < n - 1; i++)
220 {
221 bool is_common = goal[r[i]];
222 if (is_common)
223 common++;
224 }
225
226 return common;
227 }
228
229 int count_common_roads(const vector<int>& r)
230 {
231 qq++;
232 if(qq > MAX_Q)
233 // if(q > MAXQ)
234
235 wrong_answer();
236
237 return _count_common_roads_internal(r);
238 }
239
240 int main()
241 {
242 auto t1 = clock();
243
244 std::freopen("../tests/4-07.in", "r", stdin);
245 //std::freopen("4-07.out.txt", "w", stdout);
246
247 string s;
248 getline (cin,s);
249 cout<<s<<"\n";
250
251 assert(2 == scanf("%d %d", &n, &m));
CAPITOLUL 4. IOI 2017 509
17
18 bool visited[maxn] , tree[maxm];
19
20 void plant(int v)
21 {
22 visited[v] = 1;
23 for(auto e : adj[v])
24 {
25 int u = from[e] ^ to[e] ^ v;
26 if(!visited[u])
27 {
28 ind.pb(e);
29 h[u] = h[v] + 1;
30 par[u] = e;
31 tree[e] = 1;
32 plant(u);
33 }
34 else if(h[u] < h[v] - 1)
35 bc[v].pb(e);
36 }
37 }
38
39 vector<int> rem(vector<int> x , int y)
40 {
41 vector<int> nw;
42 for(auto k : x)
43 if(k != y)
44 nw.pb(k);
45
46 return nw;
47 }
48
49 bool cmp(int x , int y)
50 {
51 x = min(h[from[x]] , h[to[x]]);
52 y = min(h[from[y]] , h[to[y]]);
53
54 return x > y;
55 }
56
57 int wtf[maxm];
58
59 int get(vector<int> &bc , int sz)
60 {
61 if(!sz)
62 return 0;
63
64 vector<int> shit;
65 for(int i = 0; i < sz; i++)
66 {
67 int e = bc[i];
68 tree[wtf[e]] = 0;
69 shit.pb(e);
70 }
71
72 int ts = 0;
73 for(auto x : ind)
74 if(tree[x])
75 {
76 if(is[x] == 1)
77 ts++;
78 shit.pb(x);
79 }
80
81 for(int i = 0; i < sz; i++)
82 {
83 int e = bc[i];
84 tree[wtf[e]] = 1;
85 }
86
87 return count_common_roads(shit) - ts;
88 }
89
90 void dfs(int v)
91 {
92 for(auto e : adj[v])
CAPITOLUL 4. IOI 2017 511
93 {
94 int u = from[e] ^ to[e] ^ v;
95 if(h[u] == h[v] + 1)
96 dfs(u);
97 }
98
99 if(bc[v].empty())
100 return;
101
102 int last = v;
103
104 sort(bc[v].begin() , bc[v].end() , cmp);
105 for(auto e : bc[v])
106 {
107 while(!last);
108 wtf[e] = par[last];
109 last = from[e] ^ to[e] ^ v;
110 }
111
112 int k = bc[v].size() , st = 0 , stl = 0 , shit = get(bc[v] , k);
113 while(k && shit > st)
114 {
115 int l = stl , r = k;
116 while(r - l > 1)
117 {
118 int m = (l + r) / 2;
119 if(get(bc[v] , m) > st)
120 r = m;
121 else
122 l = m;
123 }
124
125 is[bc[v][r - 1]] = 1;
126 stl = r;
127 st++;
128 }
129
130 }
131
132 vector<int> find_roads(int n,vector<int> A,vector<int> B)
133 {
134 n = n;
135 int m = A.size();
136 for(int i = 0; i < m; i++)
137 {
138 int a = A[i] , b = B[i];
139
140 adj[a].pb(i);
141 adj[b].pb(i);
142
143 from[i] = a , to[i] = b;
144 }
145
146 plant(0);
147
148 memset(ed , -1 , sizeof ed);
149
150 num = count_common_roads(ind);
151 for(int i = 0; i < m; i++)
152 if(!tree[i])
153 {
154 int v = from[i] , u = to[i];
155 if(h[v] < h[u])
156 swap(v , u);
157
158 vector<int> ed;
159
160 bool has0 = 0;
161 while(v != u)
162 {
163 if(is[par[v]] == 0)
164 has0 = 1;
165
166 ed.pb(par[v]);
167 v = from[par[v]] ^ to[par[v]] ^ v;
168 }
CAPITOLUL 4. IOI 2017 512
169
170 if(!has0)
171 continue;
172
173 vector<int> eq;
174 for(auto e : ed)
175 {
176 if(is[e] != 0 && is[i] != 0)
177 continue;
178
179 ind = rem(ind , e);
180 ind.pb(i);
181 int nw = count_common_roads(ind);
182 ind.pop_back() , ind.pb(e);
183
184 if(nw == num)
185 {
186 if(is[e] != 0)
187 is[i] = is[e];
188 else
189 eq.pb(e);
190 }
191 else if(nw == num + 1)
192 {
193 is[i] = 1;
194 is[e] = -1;
195 }
196 else
197 {
198 is[e] = 1;
199 is[i] = -1;
200 }
201 }
202
203 if((int)eq.size() == (int)ed.size())
204 is[i] = -1;
205
206 for(auto e : eq)
207 is[e] = is[i];
208 }
209
210 for(auto x : ind)
211 if(is[x] == 0)
212 is[x] = 1;
213
214 dfs(0);
215
216 vector<int> ans;
217 for(int i = 0; i < m; i++)
218 {
219 if(!is[i])
220 is[i] = -1;
221 if(is[i] == 1)
222 ans.pb(i);
223 }
224
225 while(count_common_roads(ans) != n - 1);
226
227 return ans;
228 }
229
230 // --------- graderpublic -------------------------
231
232 static int MAXQ = 30000;
233 int MAX_Q;
234
235 static int n, m, q = 0;
236
237 static vector<int> u, v;
238 static vector<bool> goal;
239
240 static void wrong_answer()
241 {
242 printf("NO\n");
243 exit(0);
244 }
CAPITOLUL 4. IOI 2017 513
245
246 static bool is_valid(const vector<int>& r)
247 {
248 if(int(r.size()) != n - 1)
249 return false;
250
251 for(int i = 0; i < n - 1; i++)
252 if (r[i] < 0 || r[i] >= m)
253 return false;
254
255 return true;
256 }
257
258 static int _count_common_roads_internal(const vector<int>& r)
259 {
260 if(!is_valid(r))
261 wrong_answer();
262
263 int common = 0;
264 for(int i = 0; i < n - 1; i++)
265 {
266 bool is_common = goal[r[i]];
267 if (is_common)
268 common++;
269 }
270
271 return common;
272 }
273
274 int count_common_roads(const vector<int>& r)
275 {
276 q++;
277 if(q > MAX_Q)
278 // if(q > MAXQ)
279
280 wrong_answer();
281
282 return _count_common_roads_internal(r);
283 }
284
285 int main()
286 {
287 auto t1 = clock();
288
289 std::freopen("../tests/4-07.in", "r", stdin);
290 //std::freopen("4-07.out.txt", "w", stdout);
291
292 string s;
293 getline (cin,s);
294 cout<<s<<"\n";
295
296 assert(2 == scanf("%d %d", &n, &m));
297 cout<<"m="<<m<<" n="<<n<<"\n";
298
299 assert(1 == scanf("%d", &MAX_Q));
300 cout<<"MAX_Q = "<<MAX_Q<<"\n\n";
301
302 u.resize(m);
303 v.resize(m);
304
305 for(int i = 0; i < m; i++)
306 assert(2 == scanf("%d %d", &u[i], &v[i]));
307
308 goal.resize(m, false);
309
310 for(int i = 0; i < n - 1; i++)
311 {
312 int id;
313 assert(1 == scanf("%d", &id));
314 goal[id] = true;
315 }
316
317 auto t2 = clock();
318
319 vector<int> res = find_roads(n, u, v);
320
CAPITOLUL 4. IOI 2017 514
Biblioteca Naµional a Iranului se a în Teheran. Atracµia principal a bibliotecii este loca-
lizat de-a lungul unui coridor în care se a n mese, numerotate de la 0 la n 1 de la stânga la
dreapta. Pe ecare mas se a câte o carte antic scris de mân . C rµile sunt ordonate dup vâr-
sta lor, acest lucru îngreunându-i pe vizitatori s caute c rµile dup titlu. A³adar, administratorul
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
modic rile necesare pentru rearanjarea c rµilor în ordine alfabetic : pentru ecare 0 & i $ n,
cartea care se a î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 a , el poate lua aceast
carte.
a Dac are la el o carte ³i o alt carte este pe masa la care se a , el poate interschimba cele
dou c rµi.
a Dac are la el o carte ³i masa la care se a este goal , el poate pune pe mas cartea pe care
o are la el.
CAPITOLUL 4. IOI 2017 515
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
e minim .
Detalii de implementare
Voi trebue s implementaµi urm toarea procedur :
a p este un ³ir de lungime n. Cartea care se a 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 ae 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 a iniµial la masa 0. El sorteaz c rµile dup cum
urmeaz :
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.
Se observ c pe masa 0 cartea se a 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 4. IOI 2017 516
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 species 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 nd: 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 rst 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 nish sorting C1 without ever spending a
non-essential step.
If the two cycles donât 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 nishes sorting C1 and returns to S . This is optimal since the only two non-
essential steps of Minaâs 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 4. IOI 2017 518
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 rst four subtasks (see library_50.cpp for an implementation).
We could try out both options and dene 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 dene 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 le
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 4. IOI 2017 519
29
(l, r extend l, r), we look for two special cycles Cl and Cr . Cl is the rst S -containing cycle
that we encounter, when walking from l to the left. Similarly, Cr is the rst S -containing cycle
when walking from r to the right.
Let cl be the cost of reaching Cl from l (and dene 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 rst 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 nd determine the answer d π combine S, S
in linear time. The code in the le library_100.cpp implements this optimal solution.
Overview
To summarize, here are the solution techniques listed per subtask:
12 #include<ctime>
13
14 using namespace std;
15
16 const int MAX = 1000005;
17 int le[MAX], ri[MAX], pos[MAX];
18 int mark[MAX];
19
20 int val(int x)
21 {
22 return (x > 0 ? x : -x);
23 }
24
25 void go(int &l, int &r, int nl, int nr)
26 {
27 while (nl < l || r < nr)
28 if (nl != l)
29 {
30 l--;
31 nl = min(nl, le[l]);
32 nr = max(nr, ri[l]);
33 }
34 else
35 {
36 r++;
37 nl = min(nl, le[r]);
38 nr = max(nr, ri[r]);
39 }
40 }
41
42 int dist(int s, int t)
43 {
44 if (s == t)
45 return 0;
46 int ns = s;
47 if (t < s)
48 {
49 while (s >= ns)
50 {
51 ns = min(ns, le[s]);
52 s--;
53 if (ns <= t)
54 return 0;
55 }
56 }
57 else
58 {
59 while (s <= ns)
60 {
61 ns = max(ns, ri[s]);
62 s++;
63 if (ns >= t)
64 return 0;
65 }
66 }
67 return dist(s, t) + 2;
68 }
69
70 long long minimum_walk(vector<int> p, int s)
71 {
72 int n = p.size();
73 long long ans = 0;
74 for (int i = 0; i < n; i++)
75 ans += val(i - p[i]);
76 for (int i = 0; i < n; i++)
77 le[i] = ri[i] = i;
78 for (int i = 0; i < n; i++)
79 pos[p[i]] = i;
80 for (int i = 0; i < n; i++)
81 if (!mark[i])
82 {
83 int v = i;
84 while (mark[v] < 2)
85 {
86 le[v] = min(le[v], le[p[v]]);
87 ri[v] = max(ri[v], ri[p[v]]);
CAPITOLUL 4. IOI 2017 521
88 mark[v]++;
89 v = pos[v];
90 }
91 }
92 int gl = 0;
93 while (gl < s && p[gl] == gl)
94 gl++;
95 int gr = n - 1;
96 while (gr > s && p[gr] == gr)
97 gr--;
98 int l = s + 1, r = s;
99 go(l, r, s, s);
100 bool done = false;
101 while (gl < l || r < gr)
102 {
103 int nl = l, nr = r;
104 if (!done)
105 {
106 while (nl >= 0 && ri[nl] <= r)
107 nl--;
108 }
109 if (nl == -1)
110 done = true;
111 if (done)
112 {
113 nl = l;
114 if (l <= gl)
115 {
116 nr++;
117 ans += 2;
118 }
119 else
120 {
121 nl--;
122 ans += 2;
123 }
124 }
125 else
126 {
127 while (l <= le[nr])
128 nr++;
129 ans += min(dist(l - 1, nl), dist(r + 1, nr)) + 2;
130 }
131 go(l, r, nl, nr);
132 }
133 return ans;
134 }
135
136 // --------- grader ------------------------------------
137
138 int main()
139 {
140 auto t1 = clock();
141
142 std::freopen("../tests/5-29.in", "r", stdin);
143 std::freopen("5-29.out.txt", "w", stdout);
144
145 string str;
146 getline (cin,str);
147 //cout<<str<<"\n";
148
149 int n, s;
150 assert(2 == scanf("%d %d", &n, &s));
151
152 vector<int> p((unsigned) n);
153 for(int i = 0; i < n; i++)
154 assert(1 == scanf("%d", &p[(unsigned) i]));
155
156 auto t2 = clock();
157
158 long long res = minimum_walk(p, s);
159
160 auto t3 = clock();
161
162 printf("%lld\n", res);
163
CAPITOLUL 4. IOI 2017 522
50 }
51 }
52
53 for(i=0;i<n && p[i] == i; i++);
54 for(j=n-1;j>=0 && p[j] == j; j--);
55
56 l = r = s;
57 a = A[s];
58 b = B[s];
59
60 relax(l,r,a,b);
61
62 for(; l > i || r < j ;)
63 {
64 t1 = 0;
65 ll = lll = l; rr = rrr = r;
66 if(l > i)
67 {
68 for(a=l, b=r ; rr == r && ll > i ; )
69 {
70 ll--;
71 t1++;
72 a = min(A[ll],a);
73 b = max(B[ll],b);
74 relax(ll,rr,a,b);
75 }
76 if(r >= j) { t += t1; break; }
77 }
78
79 t2 = 0;
80 if(r < j)
81 {
82 for(a = l, b = r ; lll == l && rrr < j ; )
83 {
84 rrr++;
85 t2++;
86 a = min(A[rrr],a);
87 b = max(B[rrr],b);
88 relax(lll,rrr,a,b);
89 }
90 if(l <= i) { t += t2; break; }
91 }
92
93 if(rr == r) { if(lll != l) assert(0); t += t1+t2; break; }
94 t += min(t1,t2);
95 l = ll; r = rr;
96 if(lll != ll || rrr != rr) assert(0);
97 }
98
99 return x + t+t;
100 }
101
102
103 // --------- grader ------------------------------------
104
105 int main()
106 {
107 auto t1 = clock();
108
109 std::freopen("../tests/5-29.in", "r", stdin);
110 std::freopen("5-29.out.txt", "w", stdout);
111
112 string str;
113 getline (cin,str);
114 //cout<<str<<"\n";
115
116 int n, s;
117 assert(2 == scanf("%d %d", &n, &s));
118
119 vector<int> p((unsigned) n);
120 for(int i = 0; i < n; i++)
121 assert(1 == scanf("%d", &p[(unsigned) i]));
122
123 auto t2 = clock();
124
125 long long res = minimum_walk(p, s);
CAPITOLUL 4. IOI 2017 524
126
127 auto t3 = clock();
128
129 printf("%lld\n", res);
130
131 auto t4 = clock();
132
133 // reset console output
134 freopen("CON", "w", stdout);
135
136 cout<<"res = "<<res<<"\n";
137
138 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
139 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
140 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
141
142 return 0;
143 }
144 /*
145 res = 3320522632
146 t2-t1 = 1.703
147 t3-t2 = 0.172
148 t4-t3 = 0
149
150 Process returned 0 (0x0) execution time : 1.906 s
151 Press any key to continue.
152 */
46 while (1)
47 {
48 if (l <= ml) break;
49 l--, dl++, ql.push(l);
50 while (ql.size())
51 {
52 int u = ql.front();
53 ql.pop();
54 while (l > p[u])
55 {
56 l--, ql.push(l);
57 }
58 if (p[u] > s) fl = 1;
59 }
60 if (fl) break;
61 }
62
63 while (1)
64 {
65 if (r >= mr) break;
66 r++, dr++, qr.push(r);
67 while (qr.size())
68 {
69 int u = qr.front();
70 qr.pop();
71 while (r < p[u])
72 {
73 r++, qr.push(r);
74 }
75 if (p[u] < s) fr = 1;
76 }
77 if (fr) break;
78 }
79
80 if (fl && fr)
81 {
82 res += 2 * min(dl, dr);
83 while (cl > l) qu.push(--cl);
84 while (cr < r) qu.push(++cr);
85 }
86 else
87 {
88 res += 2 * (dl + dr); break;
89 }
90 }
91 return res;
92 }
93
94 // --------- grader ------------------------------------
95
96 int main()
97 {
98 auto t1 = clock();
99
100 std::freopen("../tests/5-29.in", "r", stdin);
101 std::freopen("5-29.out.txt", "w", stdout);
102
103 string str;
104 getline (cin,str);
105 //cout<<str<<"\n";
106
107 int n, s;
108 assert(2 == scanf("%d %d", &n, &s));
109
110 vector<int> p((unsigned) n);
111 for(int i = 0; i < n; i++)
112 assert(1 == scanf("%d", &p[(unsigned) i]));
113
114 auto t2 = clock();
115
116 long long res = minimum_walk(p, s);
117
118 auto t3 = clock();
119
120 printf("%lld\n", res);
121
CAPITOLUL 4. IOI 2017 526
51 {
52 int x = q.front();
53 q.pop();
54 if (p[x] > s)
55 {
56 found_l = true;
57 }
58
59 while (new_l > p[x])
60 {
61 q.push(--new_l);
62 }
63 }
64 }
65
66 while (new_r < r && !found_r)
67 {
68 q.push(++new_r);
69 ++cost_r;
70 while (!q.empty())
71 {
72 int x = q.front();
73 q.pop();
74 if (p[x] < s)
75 {
76 found_r = true;
77 }
78
79 while (new_r < p[x])
80 {
81 q.push(++new_r);
82 }
83 }
84 }
85
86 if (found_l && found_r)
87 {
88 ans += min(cost_l, cost_r) << 1;
89 while (cur_l > new_l)
90 {
91 q.push(--cur_l);
92 }
93
94 while (cur_r < new_r)
95 {
96 q.push(++cur_r);
97 }
98 }
99 else
100 {
101 ans += cost_l + cost_r << 1;
102 break;
103 }
104 }
105
106 return ans;
107 }
108
109 // --------- grader ------------------------------------
110
111 int main()
112 {
113 auto t1 = clock();
114
115 std::freopen("../tests/5-29.in", "r", stdin);
116 std::freopen("5-29.out.txt", "w", stdout);
117
118 string str;
119 getline (cin,str);
120 //cout<<str<<"\n";
121
122 int n, s;
123 assert(2 == scanf("%d %d", &n, &s));
124
125 vector<int> p((unsigned) n);
126 for(int i = 0; i < n; i++)
CAPITOLUL 4. IOI 2017 528
41 s = R;
42 }
43
44 if(s < L)
45 {
46 res += (L - s) << 1;
47 s = L;
48 }
49
50 int tmn = s, tmx = s;
51 for(int i = L; i <= R; i++)
52 {
53 res += abs(p[i] - i);
54 if(1LL * (tmx - p[i]) * (tmx - i) <= 0 ||
55 1LL * (tmn - p[i]) * (tmn - i) <= 0)
56 {
57 tmx = max(tmx, max(i, p[i]));
58 tmn = min(tmn, min(i, p[i]));
59 }
60 }
61
62 int l, r, mn = min(s, p[s]), mx = max(s, p[s]);
63 l = r = s;
64 push(l, r, tmn, tmx, p);
65
66 l = r = s;
67 push(l, r, mn, mx, p);
68
69 while(mn != tmn || mx != tmx)
70 {
71 res += 2;
72 if(mn != tmn)mn--;
73 if(mx != tmx)mx++;
74 push(l, r, mn, mx, p);
75 }
76
77 for(; l >= L; l--)
78 {
79 if(mn > l) res += 2;
80 mn = min(mn, p[l]);
81 }
82
83 for(; r <= R; r++)
84 {
85 if(mx < r) res += 2;
86 mx = max(mx, p[r]);
87 }
88 return res;
89 }
90
91 // --------- grader ------------------------------------
92
93 int main()
94 {
95 auto t1 = clock();
96
97 std::freopen("../tests/5-29.in", "r", stdin);
98 std::freopen("5-29.out.txt", "w", stdout);
99
100 string str;
101 getline (cin,str);
102 //cout<<str<<"\n";
103
104 int n, s;
105 assert(2 == scanf("%d %d", &n, &s));
106
107 vector<int> p((unsigned) n);
108 for(int i = 0; i < n; i++)
109 assert(1 == scanf("%d", &p[(unsigned) i]));
110
111 auto t2 = clock();
112
113 long long res = minimum_walk(p, s);
114
115 auto t3 = clock();
116
CAPITOLUL 4. IOI 2017 530
49
50 int l = s, r = s;
51 while(x < l || r < y)
52 {
53 extend(l, r);
54 int al = l, ar = r;
55 int bl = l, br = r;
56 long long ca = 0, cb = 0;
57
58 while(x < al && ar == r) ca += 2, extend(--al, ar);
59
60 while(bl == l && br < y) cb += 2, extend(bl, ++br);
61
62 if(ar != r && bl != l) ans += min(ca, cb);
63 else ans += ca + cb;
64
65 l = min(al, bl), r = max(ar, br);
66 }
67 return ans;
68 }
69
70 // --------- grader ------------------------------------
71
72 int main()
73 {
74 auto t1 = clock();
75
76 std::freopen("../tests/5-29.in", "r", stdin);
77 std::freopen("5-29.out.txt", "w", stdout);
78
79 string str;
80 getline (cin,str);
81 //cout<<str<<"\n";
82
83 int n, s;
84 assert(2 == scanf("%d %d", &n, &s));
85
86 vector<int> p((unsigned) n);
87 for(int i = 0; i < n; i++)
88 assert(1 == scanf("%d", &p[(unsigned) i]));
89
90 auto t2 = clock();
91
92 long long res = minimum_walk(p, s);
93
94 auto t3 = clock();
95
96 printf("%lld\n", res);
97
98 auto t4 = clock();
99
100 // reset console output
101 freopen("CON", "w", stdout);
102
103 cout<<"res = "<<res<<"\n";
104
105 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
106 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
107 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
108
109 return 0;
110 }
111 /*
112 res = 3320522632
113 t2-t1 = 1.953
114 t3-t2 = 0.172
115 t4-t3 = 0
116
117 Process returned 0 (0x0) execution time : 2.156 s
118 Press any key to continue.
119 */
2
3 #include <bits/stdc++.h>
4 #include "books.h"
5
6 using namespace std;
7
8 long long minimum_walk(vector<int> p, int s)
9 {
10 int i = s;
11 int j = s-1;//incl-incl
12 int mi = s, ma=s;
13 int n = p.size();
14 long long cnt = 0, curl = 0, curr = 0;
15 int b = 0, e = n;
16 for(int k = 0; k<s&&p[k]==k; k++) b = k+1;
17 for(int k = n-1; k>s&&p[k]==k; k--) e = k;
18
19
20 while(i>b||j<e-1)
21 {
22 bool bol = false;
23 while(mi < i)
24 {
25 bol = true;
26 i--;
27 if(p[i]>s)
28 {
29 cnt += curl;
30 curl = 0;
31 curr = 0;
32 }
33 mi = min(mi, p[i]);
34 ma = max(ma, p[i]);
35 }
36
37 while(j<ma)
38 {
39 bol = true;
40 j++;
41 if(p[j]<s)
42 {
43 cnt+=curr;
44 curl = 0;
45 curr = 0;
46 }
47 mi = min(mi, p[j]);
48 ma = max(ma, p[j]);
49
50 }
51
52 if(!bol)
53 {
54 if(mi>b){mi--;curl+=2;}
55 if(ma<e-1){ma++;curr+=2;}
56 }
57
58 }
59
60 cnt+=curl+curr;
61 for(int ii = 0; ii<n; ii++)
62 {
63 cnt += abs(ii - p[ii]);
64 }
65
66 return cnt;
67 }
68
69 // --------- grader ------------------------------------
70
71 int main()
72 {
73 auto t1 = clock();
74
75 std::freopen("../tests/5-29.in", "r", stdin);
76 std::freopen("5-29.out.txt", "w", stdout);
77
CAPITOLUL 4. IOI 2017 533
78 string str;
79 getline (cin,str);
80 //cout<<str<<"\n";
81
82 int n, s;
83 assert(2 == scanf("%d %d", &n, &s));
84
85 vector<int> p((unsigned) n);
86 for(int i = 0; i < n; i++)
87 assert(1 == scanf("%d", &p[(unsigned) i]));
88
89 auto t2 = clock();
90
91 long long res = minimum_walk(p, s);
92
93 auto t3 = clock();
94
95 printf("%lld\n", res);
96
97 auto t4 = clock();
98
99 // reset console output
100 freopen("CON", "w", stdout);
101
102 cout<<"res = "<<res<<"\n";
103
104 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
105 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
106 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
107
108 return 0;
109 }
110 /*
111 res = 3320522632
112 t2-t1 = 1.843
113 t3-t2 = 0.047
114 t4-t3 = 0
115
116 Process returned 0 (0x0) execution time : 1.938 s
117 Press any key to continue.
118 */
32 while (!vis[cur])
33 {
34 L[cyc] = min(L[cyc], cur);
35 R[cyc] = max(R[cyc], cur);
36 C[cur] = cyc;
37 vis[cur] = true;
38 cur = P[cur];
39 }
40 cyc++;
41 }
42
43 for (int i=1; i<=N; i++)
44 {
45 if (P[i] != i)
46 {
47 eL = i;
48 break;
49 }
50 }
51
52 for (int i=N; i>=1; i--)
53 {
54 if (P[i] != i)
55 {
56 eR = i;
57 break;
58 }
59 }
60
61 while (Lcur > eL || Rcur < eR)
62 {
63 //expand left and right as much as frontier allows
64 int pt1 = Lcur, pt2 = Rcur; //[Lcur, Rcur] can be reached
65 while (pt1 >= Lcur || pt2 <= Rcur)
66 {
67 if (pt1 >= Lcur)
68 {
69 Lcur = min(Lcur, L[C[pt1]]);
70 Rcur = max(Rcur, R[C[pt1]]);
71 pt1--;
72 }
73 if (pt2 <= Rcur)
74 {
75 Lcur = min(Lcur, L[C[pt2]]);
76 Rcur = max(Rcur, R[C[pt2]]);
77 pt2++;
78 }
79 }
80
81 //if one boundary is reached
82 if (Lcur <= eL && Rcur >= eR)
83 {
84 break;
85 }
86 else if (Lcur <= eL)
87 {
88 ans+=2;
89 Rcur++;
90 }
91 else if (Rcur >= eR)
92 {
93 ans+=2;
94 Lcur--;
95 }
96 else
97 {
98 //test expand right Cost to go beyond
99 int tmpL = Lcur, tmpR = Rcur, ptL = Lcur, ptR = Rcur;
100 int Lcost = 0, Rcost = 0;
101 bool root = true;
102
103 //check R cost:
104 while (ptR <= eR)
105 {
106 if (ptR > tmpR) {tmpR = ptR, Rcost++;}
107 tmpR = max(tmpR, R[C[ptR]]);
CAPITOLUL 4. IOI 2017 535
184
185 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
186 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
187 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
188
189 return 0;
190 }
191 /*
192 res = 3320522632
193 t2-t1 = 1.781
194 t3-t2 = 0.125
195 t4-t3 = 0
196
197 Process returned 0 (0x0) execution time : 1.938 s
198 Press any key to continue.
199 */
IOI 201630
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 e g se³te un subset de molecule cu greutate total în intervalul de
detectare, e determin c nu exist un asemenea subset.
Detalii de implementare
Trebuie s implementezi funcµia (metoda):
537
CAPITOLUL 5. IOI 2016 538
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 ³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 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
22 forn(i, n)
23 wp[i] = pii(w[i], i);
24 sort(wp.begin(), wp.end());
25 vector<ll> mi(n + 1), ma(n + 1);
26
27 forn(i, n)
28 {
29 mi[i + 1] = mi[i] + wp[i].first;
30 ma[i + 1] = ma[i] + wp[n - i - 1].first;
31 }
32
33 forn(i, n + 1)
34 if (mi[i] <= u && ma[i] >= l)
35 {
36 int pos = n - 1;
37 ll sum = mi[i];
38 vector<int> result(i);
39 forn(j, i)
40 {
41 while (pos >= i && sum + wp[pos].first - wp[j].first > u)
42 pos--;
43 if (pos >= i && sum + wp[pos].first - wp[j].first <= u)
44 sum += wp[pos].first - wp[j].first, result[j]
45 = wp[pos--].second;
46 else
47 result[j] = wp[j].second;
48 }
49 return result;
50 }
51
52 return vector<int>();
53 }
54
55 // BEGIN CUT
56 int main()
57 {
58 auto t1 = clock();
59
60 std::freopen("../tests/subtask_6/108", "r", stdin);
61 std::freopen("6-108.out.txt", "w", stdout);
62
63 int n, l, u;
64 scanf("%d %d %d", &n, &l, &u);
65
66 std::vector<int> w(n);
67 for (int i = 0; i < n; i++)scanf("%d", &w[i]);
68
69 auto t2 = clock();
70
71 std::vector<int> result = find_subset(l, u, w);
72
73 auto t3 = clock();
74
75 // BEGIN SECRET
76 puts("14e047d7a2907b9034950b074822b302");
77 // END SECRET
78
79 printf("%d\n", (int)result.size());
80 for (int x : result) printf("%d ", x);
81 printf("\n");
82
83 auto t4 = clock();
84
85 // reset console output
86 freopen("CON", "w", stdout);
87
88 cout<<"result.size() = "<<(int)result.size()<<"\n\n";
89
90 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
91 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
92 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
93
94 return 0;
95 }
96 // END CUT
97 /*
CAPITOLUL 5. IOI 2016 541
98 result.size() = 1000
99
100 t2-t1 = 0.39
101 t3-t2 = 0.297
102 t4-t3 = 0
103
104 Process returned 0 (0x0) execution time : 0.734 s
105 Press any key to continue.
106 */
64 auto t3 = clock();
65
66 // BEGIN SECRET
67 puts("14e047d7a2907b9034950b074822b302");
68 // END SECRET
69
70 printf("%d\n", (int)result.size());
71 for (int x : result) printf("%d ", x);
72 printf("\n");
73
74 auto t4 = clock();
75
76 // reset console output
77 freopen("CON", "w", stdout);
78
79 cout<<"result.size() = "<<(int)result.size()<<"\n\n";
80
81 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
82 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
83 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
84
85 return 0;
86 }
87 // END CUT
88 /*
89 result.size() = 1000
90
91 t2-t1 = 0.359
92 t3-t2 = 0.281
93 t4-t3 = 0
94
95 Process returned 0 (0x0) execution time : 0.672 s
96 Press any key to continue.
97 */
39 res.push_back(wp[l].second);
40 while (r < n)
41 res.push_back(wp[r++].second);
42 return res;
43 }
44 if (l)
45 sum -= wp[l - 1].first;
46 }
47 return vector<int>();
48 }
49
50 // BEGIN CUT
51 int main()
52 {
53 auto t1 = clock();
54
55 std::freopen("../tests/subtask_6/108", "r", stdin);
56 std::freopen("6-108.out.txt", "w", stdout);
57
58 int n, l, u;
59 scanf("%d %d %d", &n, &l, &u);
60
61 std::vector<int> w(n);
62 for (int i = 0; i < n; i++)scanf("%d", &w[i]);
63
64 auto t2 = clock();
65
66 std::vector<int> result = find_subset(l, u, w);
67
68 auto t3 = clock();
69
70 // BEGIN SECRET
71 puts("14e047d7a2907b9034950b074822b302");
72 // END SECRET
73
74 printf("%d\n", (int)result.size());
75 for (int x : result) printf("%d ", x);
76 printf("\n");
77
78 auto t4 = clock();
79
80 // reset console output
81 freopen("CON", "w", stdout);
82
83 cout<<"result.size() = "<<(int)result.size()<<"\n\n";
84
85 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
86 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
87 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
88
89 return 0;
90 }
91 // END CUT
92 /*
93 result.size() = 1000
94
95 t2-t1 = 0.375
96 t3-t2 = 0.281
97 t4-t3 = 0
98
99 Process returned 0 (0x0) execution time : 0.688 s
100 Press any key to continue.
101 */
10
11 #include <fstream>
12 #include<iostream>
13 #include<ctime>
14
15 using namespace std;
16
17 #define forn(i, n) for (int i = 0; i < (int)(n); i++)
18 #define forab(i, a, b) for (int i = (a); i <= (b); i++)
19
20 typedef pair <int, int> pii;
21 typedef long long ll;
22
23 // return value: result if solution exists and empty vector otherwise
24 vector<int> find_subset( int L, int U, vector<int> w )
25 {
26 int n = w.size();
27 vector<pii> wp(n);
28 forn(i, n)
29 wp[i] = pii(w[i], i);
30
31 sort(wp.begin(), wp.end());
32
33 double k0 = L / (accumulate(w.begin(), w.end(), 0.0) / n);
34
35 vector<ll> pref(n + 1);
36 forn(i, n)
37 pref[i + 1] = pref[i] + wp[i].first;
38 forab(k, (int)floor(k0), (int)ceil(k0))
39 if (1 <= k && k <= n)
40 forn(l, n - k + 1)
41 {
42 ll sum = pref[l + k] - pref[l];
43 if (L <= sum && sum <= U)
44 {
45 vector<int> res;
46 forn(i, k)
47 res.push_back(wp[l + i].second);
48 return res;
49 }
50 }
51 return vector<int>();
52 }
53
54 // BEGIN CUT
55 int main()
56 {
57 auto t1 = clock();
58
59 std::freopen("../tests/subtask_6/108", "r", stdin);
60 std::freopen("6-108.out.txt", "w", stdout);
61
62 int n, l, u;
63 scanf("%d %d %d", &n, &l, &u);
64
65 std::vector<int> w(n);
66 for (int i = 0; i < n; i++)scanf("%d", &w[i]);
67
68 auto t2 = clock();
69
70 std::vector<int> result = find_subset(l, u, w);
71
72 auto t3 = clock();
73
74 // BEGIN SECRET
75 puts("14e047d7a2907b9034950b074822b302");
76 // END SECRET
77
78 printf("%d\n", (int)result.size());
79 for (int x : result) printf("%d ", x);
80 printf("\n");
81
82 auto t4 = clock();
83
84 // reset console output
85 freopen("CON", "w", stdout);
CAPITOLUL 5. IOI 2016 545
86
87 cout<<"result.size() = "<<(int)result.size()<<"\n\n";
88
89 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
90 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
91 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
92
93 return 0;
94 }
95 // END CUT
96 /*
97 result.size() = 1000
98
99 t2-t1 = 0.359
100 t3-t2 = 0.297
101 t4-t3 = 0
102
103 Process returned 0 (0x0) execution time : 0.688 s
104 Press any key to continue.
105 */
53 }
54 }
55
56 return res;
57 }
58
59 // BEGIN CUT
60 int main()
61 {
62 auto t1 = clock();
63
64 std::freopen("../tests/subtask_6/108", "r", stdin);
65 std::freopen("6-108.out.txt", "w", stdout);
66
67 int n, l, u;
68 scanf("%d %d %d", &n, &l, &u);
69
70 std::vector<int> w(n);
71 for (int i = 0; i < n; i++)scanf("%d", &w[i]);
72
73 auto t2 = clock();
74
75 std::vector<int> result = find_subset(l, u, w);
76
77 auto t3 = clock();
78
79 // BEGIN SECRET
80 puts("14e047d7a2907b9034950b074822b302");
81 // END SECRET
82
83 printf("%d\n", (int)result.size());
84 for (int x : result) printf("%d ", x);
85 printf("\n");
86
87 auto t4 = clock();
88
89 // reset console output
90 freopen("CON", "w", stdout);
91
92 cout<<"result.size() = "<<(int)result.size()<<"\n\n";
93
94 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
95 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
96 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
97
98 return 0;
99 }
100 // END CUT
101 /*
102 result.size() = 1000
103
104 t2-t1 = 0.359
105 t3-t2 = 0.109
106 t4-t3 = 0
107
108 Process returned 0 (0x0) execution time : 0.516 s
109 Press any key to continue.
110 */
15 {
16 vector<int> V;
17 ll N=w.size();
18 ll S=0;
19 vector<pair<ll,int>> W;
20
21 for(ll i=0;i<N;i++)
22 W.push_back({w[i],i});
23
24 sort(W.begin(), W.end());
25
26 for(ll a=0,b=0;a<N;a++)
27 {
28 S-=a?W[a-1].first:0;
29 while(l>S and b<N)
30 S+=W[b++].first;
31 if(l<=S and S<=u)
32 {
33 for(ll i=a;i<b;i++)
34 V.push_back(W[i].second);
35 return V;
36 }
37 }
38
39 return V;
40 }
41
42 // BEGIN CUT
43 int main()
44 {
45 auto t1 = clock();
46
47 std::freopen("../tests/subtask_6/108", "r", stdin);
48 std::freopen("6-108.out.txt", "w", stdout);
49
50 int n, l, u;
51 scanf("%d %d %d", &n, &l, &u);
52
53 std::vector<int> w(n);
54 for (int i = 0; i < n; i++)scanf("%d", &w[i]);
55
56 auto t2 = clock();
57
58 std::vector<int> result = find_subset(l, u, w);
59
60 auto t3 = clock();
61
62 // BEGIN SECRET
63 puts("14e047d7a2907b9034950b074822b302");
64 // END SECRET
65
66 printf("%d\n", (int)result.size());
67 for (int x : result) printf("%d ", x);
68 printf("\n");
69
70 auto t4 = clock();
71
72 // reset console output
73 freopen("CON", "w", stdout);
74
75 cout<<"result.size() = "<<(int)result.size()<<"\n\n";
76
77 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
78 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
79 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
80
81 return 0;
82 }
83 // END CUT
84 /*
85 result.size() = 1000
86
87 t2-t1 = 0.343
88 t3-t2 = 0.313
89 t4-t3 = 0
90
CAPITOLUL 5. IOI 2016 548
70 puts("14e047d7a2907b9034950b074822b302");
71 // END SECRET
72
73 printf("%d\n", (int)result.size());
74 for (int x : result) printf("%d ", x);
75 printf("\n");
76
77 auto t4 = clock();
78
79 // reset console output
80 freopen("CON", "w", stdout);
81
82 cout<<"result.size() = "<<(int)result.size()<<"\n\n";
83
84 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
85 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
86 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
87
88 return 0;
89 }
90 // END CUT
91 /*
92 result.size() = 1000
93
94 t2-t1 = 0.359
95 t3-t2 = 0.312
96 t4-t3 = 0
97
98 Process returned 0 (0x0) execution time : 0.703 s
99 Press any key to continue.
100 */
42 }
43
44 // BEGIN CUT
45 int main()
46 {
47 auto t1 = clock();
48
49 std::freopen("../tests/subtask_6/108", "r", stdin);
50 std::freopen("6-108.out.txt", "w", stdout);
51
52 int n, l, u;
53 scanf("%d %d %d", &n, &l, &u);
54
55 std::vector<int> w(n);
56 for (int i = 0; i < n; i++)scanf("%d", &w[i]);
57
58 auto t2 = clock();
59
60 std::vector<int> result = find_subset(l, u, w);
61
62 auto t3 = clock();
63
64 // BEGIN SECRET
65 puts("14e047d7a2907b9034950b074822b302");
66 // END SECRET
67
68 printf("%d\n", (int)result.size());
69 for (int x : result) printf("%d ", x);
70 printf("\n");
71
72 auto t4 = clock();
73
74 // reset console output
75 freopen("CON", "w", stdout);
76
77 cout<<"result.size() = "<<(int)result.size()<<"\n\n";
78
79 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
80 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
81 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
82
83 return 0;
84 }
85 // END CUT
86 /*
87 result.size() = 1000
88
89 t2-t1 = 0.359
90 t3-t2 = 0.203
91 t4-t3 = 0
92
93 Process returned 0 (0x0) execution time : 0.594 s
94 Press any key to continue.
95 */
19
20 int idx=0;
21 long long sum=0ll;
22 for(int i=0; i<n; i++)
23 {
24 for(; idx<n && sum<l; idx++)
25 sum+=v[idx].first;
26
27 if(sum>=l && sum<=u)
28 {
29 vector<int>res;
30 for(int j=i; j<idx; j++)
31 res.push_back(v[j].second);
32
33 sort(res.begin(), res.end());
34
35 return res;
36 }
37
38 sum-=v[i].first;
39 }
40 return vector<int>();
41 }
42
43 // BEGIN CUT
44 int main()
45 {
46 auto t1 = clock();
47
48 std::freopen("../tests/subtask_6/108", "r", stdin);
49 std::freopen("6-108.out.txt", "w", stdout);
50
51 int n, l, u;
52 scanf("%d %d %d", &n, &l, &u);
53
54 std::vector<int> w(n);
55 for (int i = 0; i < n; i++)scanf("%d", &w[i]);
56
57 auto t2 = clock();
58
59 std::vector<int> result = find_subset(l, u, w);
60
61 auto t3 = clock();
62
63 // BEGIN SECRET
64 puts("14e047d7a2907b9034950b074822b302");
65 // END SECRET
66
67 printf("%d\n", (int)result.size());
68 for (int x : result) printf("%d ", x);
69 printf("\n");
70
71 auto t4 = clock();
72
73 // reset console output
74 freopen("CON", "w", stdout);
75
76 cout<<"result.size() = "<<(int)result.size()<<"\n\n";
77
78 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
79 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
80 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
81
82 return 0;
83 }
84 // END CUT
85 /*
86 result.size() = 1000
87
88 t2-t1 = 0.343
89 t3-t2 = 0.282
90 t4-t3 = 0
91
92 Process returned 0 (0x0) execution time : 0.672 s
93 Press any key to continue.
94 */
CAPITOLUL 5. IOI 2016 552
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 nal a roller-coaster-ului. în aceast
problem , vom considera c trenul este punctiform (are lungime egal cu 0).
Pentru ecare 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 e mai mic sau egal cu si
km/h.
` atunci când p r se³te acest sector, viteza trenului va exact ti km/h, indiferent de viteza
cu care trenul a intrat în acest sector.
Roller-coaster-ul va asamblat din aceste n sectoare speciale, care vor 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 ec rui segment de cale
ferat . Lungimea unui segment este m surat în metri ³i poate 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 nal 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 e minim . În subtask-
ul 3 trebuie doar s vericaµi dac exist o ordonare a sectoarelor speciale astfel încât aceast
lungime total s e 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 5. IOI 2016 553
Î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 nalul 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 nal 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 suce).
Consider an innite 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 sucient 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 eciently, 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.
8
9 using namespace std;
10
11 #define mp make_pair
12 #define pb push_back
13 #define fs first
14 #define sc second
15
16 typedef long long int64;
17
18 const int INF = (int) 1e9;
19
20 int dsu_get(vector<int>& p, int u)
21 {
22 return (u == p[u]) ? u : (p[u] = dsu_get(p, p[u]));
23 }
24
25 bool dsu_union(vector<int>& p, int u, int v)
26 {
27 u = dsu_get(p, u), v = dsu_get(p, v);
28 p[u] = v;
29 return (u != v);
30 }
31
32 int64 plan_roller_coaster(vector<int> s, vector<int> t)
33 {
34 int n = (int) s.size();
35 vector< pair< int, pair< int, int > > > e, edges;
36
37 for (int i = 0; i < n; ++i)
38 {
39 e.pb(mp(s[i], mp(1, i)));
40 e.pb(mp(t[i], mp(-1, i)));
41 }
42
43 e.pb(mp(INF, mp(1, n)));
44 e.pb(mp(1, mp(-1, n)));
45 n++;
46 vector<int> p(n);
47
48 for (int i = 0; i < n; ++i)
49 {
50 p[i] = i;
51 }
52
53 sort(e.begin(), e.end());
54
55 int64 res = 0;
56 for (int i = 0, delta = 0; i + 1 < (int) e.size(); ++i)
57 {
58 delta += e[i].sc.fs;
59 res += max(0, delta) * (int64) (e[i + 1].fs - e[i].fs);
60 edges.pb(mp(e[i + 1].fs - e[i].fs, mp(e[i].sc.sc, e[i + 1].sc.sc)));
61 if ((e[i + 1].fs == e[i].fs) || (delta != 0))
62 dsu_union(p, e[i].sc.sc, e[i + 1].sc.sc);
63 }
64
65 sort(edges.begin(), edges.end());
66
67 for (int i = 0; i < (int) edges.size(); ++i)
68 if (dsu_union(p, edges[i].sc.fs, edges[i].sc.sc))
69 res += edges[i].fs;
70
71 return res;
72 }
73
74 int main()
75 {
76 auto t1 = clock();
77
78 std::freopen("../tests/subtask_4/092", "r", stdin);
79 std::freopen("4-092.out.txt", "w", stdout);
80
81 int n, need_answer;
82
83 scanf("%d", &n);
CAPITOLUL 5. IOI 2016 556
84
85 std::vector<int> s(n), t(n);
86
87 for (int i = 0; i < n; ++i)
88 scanf("%d%d", &s[i], &t[i]);
89
90 auto t2 = clock();
91
92 long long ans = plan_roller_coaster(s, t);
93
94 auto t3 = clock();
95
96 printf("%lld\n", ans);
97
98 auto t4 = clock();
99
100 // reset console output
101 freopen("CON", "w", stdout);
102
103 cout<<"ans = "<<ans<<"\n\n";
104
105 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
106 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
107 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
108
109 return 0;
110 }
111 /*
112 ans = 309419403
113
114 t2-t1 = 0.703
115 t3-t2 = 1.563
116 t4-t3 = 0
117
118 Process returned 0 (0x0) execution time : 2.313 s
119 Press any key to continue.
120 */
36 return w<x.w;
37 }
38 };
39
40 ll boss[200005];
41
42 ll finds(ll a)
43 {
44 if(a==boss[a]) return a;
45 return boss[a]=finds(boss[a]);
46 }
47
48 void Union(ll a,ll b)
49 {
50 a=finds(a),b=finds(b);
51 if(a==b) return;
52 boss[a]=b;
53 }
54
55 ll plan_roller_coaster(vector<int> s,vector<int> t)
56 {
57 ll n=s.size()+1,ans=0,nw=0;
58 vector<mode> v;
59 vector<pii> interesting;
60 vector<edge> e;
61 s.pb(1000000001),t.pb(1);
62
63 for(int i=0;i<n;++i)
64 boss[i]=i,v.pb(mode{s[i],1,i}),v.pb(mode{t[i],-1,i});
65
66 sort(ALL(v));
67
68 for(int i=0,t=0;i+1<v.size();)
69 {
70 interesting.pb(MP(v[i].p,v[i].i));
71 while(t<v.size()&&v[i].p==v[t].p)
72 nw+=v[t].v,++t;
73 if(nw>0)
74 ans+=nw*(v[t].p-v[i].p);
75 if(nw!=0)
76 Union(v[t].i,v[i].i);
77 for(++i;i<t;++i)
78 Union(v[i-1].i,v[i].i);
79 }
80
81 for(int i=0;i+1<interesting.size();++i)
82 if(finds(interesting[i].S)!=finds(interesting[i+1].S))
83 e.pb(edge{interesting[i].S,
84 interesting[i+1].S,
85 interesting[i+1].F-interesting[i].F});
86 sort(ALL(e));
87
88 for(auto i:e)
89 if(finds(i.a)!=finds(i.b))
90 Union(i.a,i.b),ans+=i.w;
91
92 return ans;
93 }
94
95 int main()
96 {
97 auto t1 = clock();
98
99 std::freopen("../tests/subtask_4/092", "r", stdin);
100 std::freopen("4-092.out.txt", "w", stdout);
101
102 int n, need_answer;
103
104 scanf("%d", &n);
105
106 std::vector<int> s(n), t(n);
107
108 for (int i = 0; i < n; ++i)
109 scanf("%d%d", &s[i], &t[i]);
110
111 auto t2 = clock();
CAPITOLUL 5. IOI 2016 558
112
113 long long ans = plan_roller_coaster(s, t);
114
115 auto t3 = clock();
116
117 printf("%lld\n", ans);
118
119 auto t4 = clock();
120
121 // reset console output
122 freopen("CON", "w", stdout);
123
124 cout<<"ans = "<<ans<<"\n\n";
125
126 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
127 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
128 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
129
130 return 0;
131 }
132 /*
133 ans = 309419403
134
135 t2-t1 = 0.745
136 t3-t2 = 0.893
137 t4-t3 = 0
138
139 Process returned 0 (0x0) execution time : 1.669 s
140 Press any key to continue.
141 */
43 in[s[i]].push_back(i);
44 in[t[i]].push_back(i);
45 }
46
47 long long res = 0;
48 int bal = 0, last = 0, lastid = n;
49
50 for(auto x : sw)
51 {
52 if(bal > 0)
53 {
54 res += 1LL * bal * (x.ff - last);
55 }
56 for(int y : in[x.ff])
57 {
58 f.push_back({ bal == 0 ? x.ff - last : 0, {y, lastid}});
59 lastid = y;
60 last = x.ff;
61 }
62
63 bal += x.ss;
64 }
65
66 sort(f.begin(), f.end());
67
68 for(auto x : f)
69 res += x.ff * unite(x.ss.ff, x.ss.ss);
70
71 return res;
72 }
73
74 int main()
75 {
76 auto t1 = clock();
77
78 std::freopen("../tests/subtask_4/092", "r", stdin);
79 std::freopen("4-092.out.txt", "w", stdout);
80
81 int n, need_answer;
82
83 scanf("%d", &n);
84
85 std::vector<int> s(n), t(n);
86
87 for (int i = 0; i < n; ++i)
88 scanf("%d%d", &s[i], &t[i]);
89
90 auto t2 = clock();
91
92 long long ans = plan_roller_coaster(s, t);
93
94 auto t3 = clock();
95
96 printf("%lld\n", ans);
97
98 auto t4 = clock();
99
100 // reset console output
101 freopen("CON", "w", stdout);
102
103 cout<<"ans = "<<ans<<"\n\n";
104
105 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
106 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
107 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
108
109 return 0;
110 }
111 /*
112 ans = 309419403
113
114 t2-t1 = 0.794
115 t3-t2 = 3.261
116 t4-t3 = 0
117
118 Process returned 0 (0x0) execution time : 4.500 s
CAPITOLUL 5. IOI 2016 560
71
72 int n, need_answer;
73
74 scanf("%d", &n);
75
76 std::vector<int> s(n), t(n);
77
78 for (int i = 0; i < n; ++i)
79 scanf("%d%d", &s[i], &t[i]);
80
81 auto t2 = clock();
82
83 long long ans = plan_roller_coaster(s, t);
84
85 auto t3 = clock();
86
87 printf("%lld\n", ans);
88
89 auto t4 = clock();
90
91 // reset console output
92 freopen("CON", "w", stdout);
93
94 cout<<"ans = "<<ans<<"\n\n";
95
96 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
97 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
98 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
99
100 return 0;
101 }
102 /*
103 ans = 309419403
104
105 t2-t1 = 0.721
106 t3-t2 = 1.47
107 t4-t3 = 0
108
109 Process returned 0 (0x0) execution time : 2.232 s
110 Press any key to continue.
111 */
32 if(setSize[v]>setSize[u]) swap(u,v);
33 setSize[u]+=setSize[v];
34 link[v]=u;
35 }
36
37 void initDSU(int n)
38 {
39 for(int i=1;i<=n;i++)
40 {
41 setSize[i]=1;
42 link[i]=i;
43 }
44 }
45
46 struct event
47 {
48 int T;
49 int op;
50 int id; //Which special section
51 bool operator<(const event& a)
52 {
53 if(T<a.T)
54 return true;
55 else
56 {
57 if(T==a.T)
58 {
59 if(op<a.op) return true;
60 else return false;
61 }
62 else return false;
63 }
64 }
65 };
66
67 struct segment
68 {
69 ll length;
70 int a,b; //ID where it starts and ends
71 bool operator < (const segment& s)
72 {
73 return length<s.length;
74 }
75 };
76
77 vector<event> timeline;
78 vector<segment> remaining; //Not taken because its balance was 0
79
80 long long plan_roller_coaster(vector<int> s, vector<int> t)
81 {
82 int n=s.size();
83 ll cost=0;
84 initDSU(n);
85 for(int i=0;i<n;i++)
86 {
87 event e={s[i],+1,i+1};
88 timeline.push_back(e);
89 e={t[i],-1,i+1};
90 timeline.push_back(e);
91 }
92
93 sort(timeline.begin(),timeline.end());
94
95 //Lines to the right are +1
96 //Lines to the left are -1
97 ll balance=-1; //Because there is a line that goes from inf to 1
98
99 for(int i=0;i<2*n-1;i++)
100 {
101 balance+=timeline[i].op;
102 if(balance<0)
103 {
104 //Add a track from left to right (free) and connect i with i+1
105 unite(timeline[i].id,timeline[i+1].id);
106 }
107 else
CAPITOLUL 5. IOI 2016 563
108 if(balance>0)
109 {
110 //We need to slow down the train so we add "balance" tracks
111 cost+=(ll)(timeline[i+1].T-timeline[i].T)*balance;
112
113 //With length: distance between that two events
114 unite(timeline[i].id,timeline[i+1].id);
115 }
116 else
117 if(balance==0)
118 {
119 segment s;
120 s.length=(timeline[i+1].T-timeline[i].T);
121 s.a=timeline[i].id;
122 s.b=timeline[i+1].id;
123 remaining.push_back(s);
124 }
125 }
126
127 sort(remaining.begin(),remaining.end());
128
129 set<int> R; //Roots
130 for(int i=1;i<=n;i++)
131 {
132 R.insert(Find(i));
133 }
134
135 int roots=R.size();
136 int i=0;
137 while(roots>1)
138 { //Not fully connected
139 int a=remaining[i].a;
140 int b=remaining[i].b;
141 if(!same(a,b))
142 {
143 unite(a,b);
144 cost+=remaining[i].length;
145 roots--;
146 }
147 i++;
148 }
149
150 return cost;
151 }
152
153 int main()
154 {
155 auto t1 = clock();
156
157 std::freopen("../tests/subtask_4/092", "r", stdin);
158 std::freopen("4-092.out.txt", "w", stdout);
159
160 int n, need_answer;
161
162 scanf("%d", &n);
163
164 std::vector<int> s(n), t(n);
165
166 for (int i = 0; i < n; ++i)
167 scanf("%d%d", &s[i], &t[i]);
168
169 auto t2 = clock();
170
171 long long ans = plan_roller_coaster(s, t);
172
173 auto t3 = clock();
174
175 printf("%lld\n", ans);
176
177 auto t4 = clock();
178
179 // reset console output
180 freopen("CON", "w", stdout);
181
182 cout<<"ans = "<<ans<<"\n\n";
183
CAPITOLUL 5. IOI 2016 564
184 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
185 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
186 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
187
188 return 0;
189 }
190 /*
191 ans = 309419403
192
193 t2-t1 = 0.69
194 t3-t2 = 1.037
195 t4-t3 = 0
196
197 Process returned 0 (0x0) execution time : 1.779 s
198 Press any key to continue.
199 */
57 {
58 if (sum[i])
59 {
60 unite(i, i + 1);
61 if (sum[i] > 0)
62 ans += 1ll * sum[i] * (p[i + 1] - p[i]);
63 }
64 else e.eb(i);
65 }
66
67 sort(all(e), [&p](int u, int v)
68 { return p[u + 1] - p[u] < p[v + 1] - p[v]; });
69
70 trav(u, e)
71 if (unite(u, u + 1))
72 ans += p[u + 1] - p[u];
73
74 return ans;
75 }
76
77 int main()
78 {
79 auto t1 = clock();
80
81 std::freopen("../tests/subtask_4/092", "r", stdin);
82 std::freopen("4-092.out.txt", "w", stdout);
83
84 int n, need_answer;
85
86 scanf("%d", &n);
87
88 std::vector<int> s(n), t(n);
89
90 for (int i = 0; i < n; ++i)
91 scanf("%d%d", &s[i], &t[i]);
92
93 auto t2 = clock();
94
95 long long ans = plan_roller_coaster(s, t);
96
97 auto t3 = clock();
98
99 printf("%lld\n", ans);
100
101 auto t4 = clock();
102
103 // reset console output
104 freopen("CON", "w", stdout);
105
106 cout<<"ans = "<<ans<<"\n\n";
107
108 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
109 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
110 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
111
112 return 0;
113 }
114 /*
115 ans = 309419403
116
117 t2-t1 = 0.739
118 t3-t2 = 1.324
119 t4-t3 = 0
120
121 Process returned 0 (0x0) execution time : 2.094 s
122 Press any key to continue.
123 */
CAPITOLUL 5. IOI 2016 566
5.3 Shortcut
Problema 3 - Shortcut 100 de puncte
Author: Gleb Evstropov (Russia)
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 ecare 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
cele dou staµii pe care le va conecta.
Fiecare porµiune de cale ferat , inclusiv linia expres, poate 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 e minimi-
zat.
Detalii de implementare
Trebuie s implementezi funcµia
Folosiµi ³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 5. IOI 2016 567
Soluµia optim este s se construiasc linia expres între staµiile 1 ³i 3, a³a cum este ar tat în
gur .
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:
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 5. IOI 2016 568
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
o
6 k are valid. This 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 5. IOI 2016 569
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 x j > i and y < z. Now the pair
produces some square i xj ô xi + dj + di > k. Let's x j and nd 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 ' xj dj xi 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 nd 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 prex and sux maximums. Now when we
CAPITOLUL 5. IOI 2016 570
use the same solution as for subtask 6, but we query maximum and minimum values for inequality
only when 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.
104 {
105 maxsump[i] = max(maxsump[i - 1], x[i] + d[i]);
106 mindifp[i] = min(mindifp[i - 1], x[i] - d[i]);
107 }
108
109 important[n - 1] = true;
110 int curb = n - 1;
111 for (int i = n - 2; i >= 0; i--)
112 {
113 if (x[i] - d[i] < x[curb] - d[curb])
114 {
115 important[i] = true;
116 curb = i;
117 }
118 }
119
120 long long lb = 0ll;
121 long long rb = x[n - 1] + 2e9;
122 while (lb < rb)
123 {
124 long long mid = (lb + rb) / 2;
125 if (check(n, c, mid))
126 rb = mid;
127 else
128 lb = mid + 1;
129 }
130
131 return lb;
132 }
133
134 // BEGIN CUT
135 int main()
136 {
137 auto t1 = clock();
138
139 std::freopen("../tests/subtask_8/220", "r", stdin);
140 std::freopen("8-220.out.txt", "w", stdout);
141
142 int n, c;
143 scanf("%d%d", &n, &c);
144
145 vector<int> l(n - 1);
146 vector<int> d(n);
147 for (int i = 0; i < n - 1; i++)
148 scanf("%d", &l[i]);
149 for (int i = 0; i < n; i++)
150 scanf("%d", &d[i]);
151
152 auto t2 = clock();
153
154 long long t = find_shortcut(n, l, d, c);
155
156 auto t3 = clock();
157
158 // BEGIN SECRET
159 puts("14e047d7a2907b9034950b074822b302");
160 // END SECRET
161
162 printf("%lld\n", t);
163
164 auto t4 = clock();
165
166 // reset console output
167 freopen("CON", "w", stdout);
168
169 cout<<"n = "<<n<<" c = "<<c<<"\n";
170 cout<<"t = "<<t<<"\n\n";
171
172 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
173 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
174 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
175
176 return 0;
177 }
178 // END CUT
179 /*
CAPITOLUL 5. IOI 2016 575
63 T x = 0;
64 if (c == ’-’)
65 s = -1, c = getChar();
66 while (’0’ <= c && c <= ’9’)
67 x = x * 10 + c - ’0’, c = getChar();
68 return s == 1 ? x : -x;
69 }
70
71 /** Write */
72
73 static int write_pos = 0;
74 static char write_buf[buf_size];
75
76 inline void writeChar( int x )
77 {
78 if (write_pos == buf_size)
79 fwrite(write_buf, 1, buf_size, stdout), write_pos = 0;
80 write_buf[write_pos++] = x;
81 }
82
83 template <class T>
84 inline void writeInt( T x, char end )
85 {
86 if (x < 0)
87 writeChar(’-’), x = -x;
88
89 char s[24];
90 int n = 0;
91 while (x || !n)
92 s[n++] = ’0’ + x % 10, x /= 10;
93 while (n--)
94 writeChar(s[n]);
95 if (end)
96 writeChar(end);
97 }
98
99 inline void writeWord( const char *s )
100 {
101 while ( *s)
102 writeChar( *s++);
103 }
104
105 struct Flusher
106 {
107 ~Flusher() {
108 if (write_pos)
109 fwrite(write_buf, 1, write_pos, stdout), write_pos = 0;
110 }
111 } flusher;
112
113 bool isNonempty(int n)
114 {
115 if (suml > sumr || difl > difr)
116 return false;
117
118 int p = 0;
119 for (int i = 1; i < n; i++)
120 {
121 while (p < i && x[p] + x[i] <= sumr && x[p] - x[i] <= difr)
122 p++;
123 while (p > 0 && (x[p] + x[i] > sumr || x[p] - x[i] > difr))
124 p--;
125
126 if (x[i] + x[p] >= suml &&
127 x[i] + x[p] <= sumr &&
128 x[p] - x[i] >= difl &&
129 x[p] - x[i] <= difr)
130 {
131 return true;
132 }
133 }
134
135 return false;
136 }
137
138 bool check(int n, int c, long long k)
CAPITOLUL 5. IOI 2016 577
139 {
140 suml = difl = -inf;
141 sumr = difr = inf;
142
143 int p = -1;
144 deque <int> q;
145
146 for (int i = 0; i < n; i++)
147 {
148 if (important[i])
149 {
150 if (q.front() == p)
151 q.pop_front();
152
153 while (p + 1 < i && d[q.front()] - x[q.front()] > k - x[i] - d[i])
154 {
155 p++;
156 if (q.front() == p)
157 q.pop_front();
158 }
159
160 if (p != -1)
161 {
162 suml = max(suml, x[i] + d[i] - k + c + maxsump[p]);
163 sumr = min(sumr, x[i] - d[i] + k - c + mindifp[p]);
164 difl = max(difl, -x[i] + d[i] - k + c + maxsump[p]);
165 difr = min(difr, -x[i] - d[i] + k - c + mindifp[p]);
166 }
167 }
168
169 while (!q.empty() && d[q.back()] - x[q.back()] <= d[i] - x[i])
170 q.pop_back();
171
172 q.push_back(i);
173 }
174
175 return isNonempty(n);
176 }
177
178 long long find_shortcut(int n, vector <int> len, vector <int> dep, int c)
179 {
180 x[0] = 0ll;
181
182 for (int i = 0; i < n; i++)
183 {
184 d[i] = dep[i];
185 if (i + 1 < n)
186 {
187 x[i + 1] = x[i] + len[i];
188 }
189 }
190
191 maxsump[0] = d[0];
192 mindifp[0] = -d[0];
193
194 for (int i = 1; i < n; i++)
195 {
196 maxsump[i] = max(maxsump[i - 1], x[i] + d[i]);
197 mindifp[i] = min(mindifp[i - 1], x[i] - d[i]);
198 }
199
200 important[n - 1] = true;
201 int curb = n - 1;
202 for (int i = n - 2; i >= 0; i--)
203 {
204 if (x[i] - d[i] < x[curb] - d[curb])
205 {
206 important[i] = true;
207 curb = i;
208 }
209 }
210
211 long long lb = 0ll;
212 long long rb = inf;
213 while (lb < rb)
214 {
CAPITOLUL 5. IOI 2016 578
1 #include <bits/stdc++.h>
2
3 using namespace std;
4
5 using ll = long long;
6 using ld = long double;
7 using D = double;
8 using uint = unsigned int;
9
10 #ifdef WIN32
11 #define LLD "%I64d"
12 #else
13 #define LLD "%lld"
14 #endif
15
16 #define pb push_back
17 #define mp make_pair
18 #define all(x) (x).begin(),(x).end()
19 #define fi first
20 #define se second
21
22 const int maxn = 1000005;
23 const ll inf = 1e18;
24
25 ll x[maxn], d[maxn];
26 int n, C;
27 pair<ll, int> q[maxn];
28 int ans1, ans2;
29
30 bool can(ll diam)
31 {
32 bool needleft = false;
33 ll maxsum = inf;
34 ll minsum = -inf;
35 ll maxdif = inf;
36 ll mindif = -inf;
37 pair<ll, ll> mostleft = {inf, -inf};
38 pair<ll, ll> mostright = {-inf, -inf};
39 int l = 0;
40 int r = 0;
41 for (int i = 0; i < n; i++)
42 {
43 // no need to check whether it is "small" or not,
44 // because in case of "small" its square is inside "big"’s square
45 while (r > l && x[i] - q[l].fi + d[i] > diam)
46 {
47 int wh = q[l].se;
48 l++;
49 if (x[wh] - d[wh] < mostleft.fi - mostleft.se)
50 mostleft = {x[wh], d[wh]};
51 if (x[wh] + d[wh] > mostright.fi + mostright.se)
52 mostright = {x[wh], d[wh]};
53
54 needleft = true;
55 }
56 if (needleft)
57 {
58 maxsum = min(maxsum,
59 (mostleft.fi + diam - C - d[i] - mostleft.se) + x[i]);
60 minsum = max(minsum,
61 (mostright.fi - (diam - C - d[i] - mostright.se)) + x[i]);
62 maxdif = min(maxdif,
63 x[i] - (mostright.fi - (diam - C - d[i] - mostright.se)));
64 mindif = max(mindif,
65 x[i] - (mostleft.fi + diam - C - d[i] - mostleft.se));
66 }
67
68 while (r > l && q[r - 1].fi > x[i] - d[i]) r--;
69 q[r++] = {x[i] - d[i], i};
70 }
71
72 if (maxsum < minsum || maxdif < mindif) return false;
73 int curdif = 0;
74 int cursum = n;
75 for (int i = 0; i < n; i++)
76 {
CAPITOLUL 5. IOI 2016 580
153 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
154
155 return 0;
156 }
157 // END CUT
158 /*
159 n = 1000000 c = 1000
160 t = 1000857674
161
162 t2-t1 = 4.629
163 t3-t2 = 8.341
164 t4-t3 = 0
165
166 Process returned 0 (0x0) execution time : 13.030 s
167 Press any key to continue.
168 */
57
58 lint q1 = (v[i].second != mxp ? mx : smx);
59 lint q2 = (v[i].second != mnp ? mn : smn);
60 lint ca = v[i].arg1;
61 lint cb = v[i].arg2;
62
63 ps = max(ps, q1 - x + c + cb + ca);
64 pe = min(pe, q2 + x - c + cb - ca);
65 ms = max(ms, q1 - x + c - cb + ca);
66 me = min(me, q2 + x - c - cb - ca);
67 }
68
69 p = 0;
70 for(int i=0; i<n; i++)
71 {
72 lint s = max(ps - b[i], b[i] - me);
73 lint e = min(pe - b[i], b[i] - ms);
74 while(p < n && s > b[p]) p++;
75 while(p > 0 && s <= b[p-1]) p--;
76 while(p < n && b[p] <= e) return true;
77 }
78
79 return false;
80 }
81
82 long long find_shortcut(int n, std::vector<int> l,
83 std::vector<int> d, int c)
84 {
85 ::n = n;
86 ::c = c;
87
88 for(int i=0; i<n; i++)
89 {
90 a[i] = d[i];
91 if(i >= 1) b[i] = b[i-1] + l[i-1];
92 }
93
94 for(int i=0; i<n; i++)
95 {
96 v[i] = (Fucking_locality){a[i], b[i], a[i] + b[i], i};
97 w[i] = (Fucking_locality){a[i] + b[i], -a[i] + b[i], -a[i] + b[i], i};
98 }
99
100 sort(v, v+n);
101 sort(w, w+n);
102
103 lint s = 0, e = 2e15;
104 while(s != e)
105 {
106 lint m = (s+e)/2;
107 if(trial(m)) e = m;
108 else s = m+1;
109 }
110
111 return s;
112 }
113
114 // BEGIN CUT
115 int main()
116 {
117 auto t1 = clock();
118
119 std::freopen("../tests/subtask_8/220", "r", stdin);
120 std::freopen("8-220.out.txt", "w", stdout);
121
122 int n, c;
123 scanf("%d%d", &n, &c);
124
125 vector<int> l(n - 1);
126 vector<int> d(n);
127 for (int i = 0; i < n - 1; i++)
128 scanf("%d", &l[i]);
129 for (int i = 0; i < n; i++)
130 scanf("%d", &d[i]);
131
132 auto t2 = clock();
CAPITOLUL 5. IOI 2016 583
133
134 long long t = find_shortcut(n, l, d, c);
135
136 auto t3 = clock();
137
138 // BEGIN SECRET
139 puts("14e047d7a2907b9034950b074822b302");
140 // END SECRET
141
142 printf("%lld\n", t);
143
144 auto t4 = clock();
145
146 // reset console output
147 freopen("CON", "w", stdout);
148
149 cout<<"n = "<<n<<" c = "<<c<<"\n";
150 cout<<"t = "<<t<<"\n\n";
151
152 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
153 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
154 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
155
156 return 0;
157 }
158 // END CUT
159 /*
160 n = 1000000 c = 1000
161 t = 1000857674
162
163 t2-t1 = 3.546
164 t3-t2 = 8.469
165 t4-t3 = 0
166
167 Process returned 0 (0x0) execution time : 12.344 s
168 Press any key to continue.
169 */
36 }
37 else
38 if (se < mx) sei = p, se = mx;
39 ++j;
40 }
41
42 p = ad[i].second;
43 if (p == sb[0].second && j == 1 || j == 0) continue;
44
45 llong adi = (p == fsi ? se : fs);
46 llong sbi = (p == sb[0].second ? sb[1].first : sb[0].first);
47 llong adj = dist[p] + etc[p];
48 llong sbj = dist[p] - etc[p];
49
50 lsb = max(lsb, adi - sbj - m + c);
51 gsb = min(gsb, sbi - adj + m - c);
52 lad = max(lad, adi + adj - m + c);
53 gad = min(gad, sbi + sbj + m - c);
54 }
55
56 llong gpos, lpos;
57 p = 0, q = n - 1;
58 for (int i = 0; i < n; ++i)
59 {
60 gpos = min(dist[i] - lsb, gad - dist[i]);
61 lpos = max(dist[i] - gsb, lad - dist[i]);
62
63 while (p > 0 && dist[p - 1] >= lpos) --p;
64 while (p < n && dist[p] < lpos) ++p;
65 while (q >= 0 && dist[q] > gpos) --q;
66 while (q < n - 1 && dist[q + 1] <= gpos) ++q;
67
68 if (p <= q) return true;
69 }
70
71 return false;
72 }
73
74 long long find_shortcut(int N, std::vector<int> l, std::vector<int> d, int C)
75 {
76 n = N; c = C;
77 dist.resize(n);
78 llong sum = 0ll;
79 for (int i = 1; i < n; ++i)
80 {
81 sum += l[i - 1];
82 dist[i] = sum;
83 }
84
85 etc = d;
86 llong ld = 0ll, e = 0ll;
87 int fs = 0, se = 0;
88 for (int i = 0; i < n; ++i)
89 {
90 ad.push_back({ dist[i] + etc[i], i });
91 sb.push_back({ dist[i] - etc[i], i });
92
93 e = max(e, ld + etc[i]);
94
95 if (fs < etc[i])
96 {
97 se = fs;
98 fs = etc[i];
99 }
100 else
101 if (se < etc[i])
102 {
103 se = etc[i];
104 }
105
106 if (i < n - 1)
107 ld = max(ld, (llong)etc[i]) + l[i];
108 }
109
110 sort(ad.begin(), ad.end());
111 sort(sb.begin(), sb.end());
CAPITOLUL 5. IOI 2016 585
112
113 llong s = fs + se;
114 while (s < e)
115 {
116 llong m = (s + e) / 2;
117 if (check(m)) e = m;
118 else s = m + 1ll;
119 }
120
121 return s;
122 }
123
124 // BEGIN CUT
125 int main()
126 {
127 auto t1 = clock();
128
129 std::freopen("../tests/subtask_8/220", "r", stdin);
130 std::freopen("8-220.out.txt", "w", stdout);
131
132 int n, c;
133 scanf("%d%d", &n, &c);
134
135 vector<int> l(n - 1);
136 vector<int> d(n);
137 for (int i = 0; i < n - 1; i++)
138 scanf("%d", &l[i]);
139 for (int i = 0; i < n; i++)
140 scanf("%d", &d[i]);
141
142 auto t2 = clock();
143
144 long long t = find_shortcut(n, l, d, c);
145
146 auto t3 = clock();
147
148 // BEGIN SECRET
149 puts("14e047d7a2907b9034950b074822b302");
150 // END SECRET
151
152 printf("%lld\n", t);
153
154 auto t4 = clock();
155
156 // reset console output
157 freopen("CON", "w", stdout);
158
159 cout<<"n = "<<n<<" c = "<<c<<"\n";
160 cout<<"t = "<<t<<"\n\n";
161
162 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
163 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
164 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
165
166 return 0;
167 }
168 // END CUT
169 /*
170 n = 1000000 c = 1000
171 t = 1000857674
172
173 t2-t1 = 3.453
174 t3-t2 = 6.514
175 t4-t3 = 0
176
177 Process returned 0 (0x0) execution time : 10.030 s
178 Press any key to continue.
179 */
5
6 using namespace std;
7
8 const long long inf = 1ll << 60;
9
10 long long find_shortcut(int n, vector<int> l, vector<int> d, int c)
11 {
12 vector<long long> x(n);
13 for (int i = 0; i < n - 1; ++i)
14 {
15 x[i + 1] = x[i] + l[i];
16 }
17
18 auto check = [&](long long limit)
19 {
20 long long lsum = -inf, rsum = inf;
21 long long ldiff = -inf, rdiff = inf;
22 long long max_sum = -inf, min_diff = inf;
23
24 deque<int> q;
25 for (int i = 0; i < n; ++i)
26 {
27 while (!q.empty() && x[i]-x[q.front()]+d[i]+d[q.front()] > limit)
28 {
29 max_sum = max(max_sum, x[q.front()] + d[q.front()]);
30 min_diff = min(min_diff, x[q.front()] - d[q.front()]);
31 q.pop_front();
32 }
33
34 if (max_sum >= 0)
35 {
36 lsum = max(lsum, x[i] + d[i] + max_sum + c - limit);
37 rsum = min(rsum, x[i] - d[i] + min_diff + limit - c);
38 rdiff = min(rdiff, x[i] - d[i] - max_sum + limit - c);
39 ldiff = max(ldiff, x[i] + d[i] - min_diff + c - limit);
40 }
41
42 while (!q.empty() && x[i] - d[i] < x[q.back()] - d[q.back()])
43 {
44 q.pop_back();
45 }
46
47 q.push_back(i);
48 }
49
50 if (lsum > rsum || ldiff > rdiff)
51 {
52 return false;
53 }
54
55 for (int i = 0, j = n, k = 0; i < n; ++i)
56 {
57 while (j && x[j - 1] + x[i] >= lsum)
58 {
59 --j;
60 }
61
62 while (k < n && x[k] - x[i] < ldiff)
63 {
64 ++k;
65 }
66
67 int p = max(i + 1, max(j, k));
68 if (p < n && x[p] + x[i] <= rsum && x[p] - x[i] <= rdiff)
69 {
70 return true;
71 }
72 }
73
74 return false;
75 };
76
77 long long low = 0, high = inf;
78 while (low < high)
79 {
80 long long mid = low + high >> 1;
CAPITOLUL 5. IOI 2016 587
81 if (check(mid))
82 {
83 high = mid;
84 }
85 else
86 {
87 low = mid + 1;
88 }
89 }
90
91 return high;
92 }
93
94 // BEGIN CUT
95 int main()
96 {
97 auto t1 = clock();
98
99 std::freopen("../tests/subtask_8/220", "r", stdin);
100 std::freopen("8-220.out.txt", "w", stdout);
101
102 int n, c;
103 scanf("%d%d", &n, &c);
104
105 vector<int> l(n - 1);
106 vector<int> d(n);
107 for (int i = 0; i < n - 1; i++)
108 scanf("%d", &l[i]);
109 for (int i = 0; i < n; i++)
110 scanf("%d", &d[i]);
111
112 auto t2 = clock();
113
114 long long t = find_shortcut(n, l, d, c);
115
116 auto t3 = clock();
117
118 // BEGIN SECRET
119 puts("14e047d7a2907b9034950b074822b302");
120 // END SECRET
121
122 printf("%lld\n", t);
123
124 auto t4 = clock();
125
126 // reset console output
127 freopen("CON", "w", stdout);
128
129 cout<<"n = "<<n<<" c = "<<c<<"\n";
130 cout<<"t = "<<t<<"\n\n";
131
132 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
133 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
134 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
135
136 return 0;
137 }
138 // END CUT
139 /*
140 n = 1000000 c = 1000
141 t = 1000857674
142
143 t2-t1 = 3.526
144 t3-t2 = 29.047
145 t4-t3 = 0
146
147 Process returned 0 (0x0) execution time : 32.620 s
148 Press any key to continue.
149 */
4 #include <bits/stdc++.h>
5
6 #define INFLL (0x3f3f3f3f3f3f3f3fll)
7
8 using namespace std;
9
10 typedef long long ll;
11 inline void upmin(ll &a, ll b) { if(b < a) a = b; }
12 inline void upmax(ll &a, ll b) { if(a < b) a = b; }
13
14 const int MAXN = 1000005;
15
16 ll Mx0[MAXN], Mx1[MAXN];
17 ll X[MAXN], L[MAXN], TP[MAXN], TM[MAXN];
18 int O[MAXN], OJ[MAXN];
19
20 int N; ll K, Ans;
21
22 bool isp(ll Y)
23 {
24 ll xymx = -INFLL, xymn = INFLL, yxmx = -INFLL, yxmn = INFLL, rmn, rmx;
25 for(int oi = 0, oj = 0, j; oj < N; oj++)
26 {
27 j = OJ[oj]; ll t = Y-TP[j];
28 for(; oi < N && t < TM[O[oi]]; oi++);
29 if(!oi || (1 == oi && j == O[0])) continue;
30 rmx = TP[j] == Mx0[oi-1] ? Mx1[oi-1] : Mx0[oi-1];
31 rmn = -(j == O[0] ? TM[O[1]] : TM[O[0]]);
32 ll a = Y-K - TM[j], b = K-Y + TP[j];
33 upmin(xymn, a+rmn); upmax(xymx, b+rmx);
34 upmin(yxmn, a-rmx); upmax(yxmx, b-rmn);
35 if(xymn < xymx || yxmn < yxmx) return false;
36 }
37
38 for(int s = 0, e = 0; s < N; s++)
39 {
40 rmn = max(xymx-X[s], yxmx+X[s]);
41 rmx = min(xymn-X[s], yxmn+X[s]);
42 if(rmx < rmn) continue;
43 for(; e+1 < N && X[e] < rmn; e++);
44 for(; e && rmx < X[e]; e--);
45 if(rmn <= X[e]) return true;
46 }
47
48 return false;
49 }
50
51 ll getAns()
52 {
53 ll mx = -INFLL;
54 for(int i = 0; i < N; i++)
55 {
56 upmax(Ans, X[i]+L[i] + mx);
57 upmax(mx, L[i]-X[i]);
58 TP[i] = X[i]+L[i];
59 TM[i] = L[i]-X[i];
60 }
61
62 iota(O, O+N, 0);
63 sort(O, O+N, [&](int a, int b) {return TM[a] > TM[b];});
64
65 iota(OJ, OJ+N, 0);
66 sort(OJ, OJ+N, [&](int a, int b) {return TP[a] < TP[b];});
67
68 Mx0[0] = Mx1[0] = -INFLL;
69 for(int oi = 0, i; oi < N; oi++)
70 {
71 if(oi)
72 {
73 Mx0[oi] = Mx0[oi-1];
74 Mx1[oi] = Mx1[oi-1];
75 }
76
77 i = O[oi]; ll c = TP[i];
78 if(Mx0[oi] < c) swap(Mx0[oi], c);
79 if(Mx1[oi] < c) swap(Mx1[oi], c);
CAPITOLUL 5. IOI 2016 589
80 }
81
82 ll a = 0, b = 0;
83 for(int i = 0; i < N; i++)
84 {
85 ll c = L[i];
86 if(a < c) swap(a, c);
87 if(b < c) swap(b, c);
88 }
89
90 ll s = a+b, e = Ans;
91 for(ll m; s < e;)
92 {
93 m = (s+e) >> 1;
94 if(isp(m)) e = m;
95 else s = m+1;
96 }
97
98 return s;
99 }
100
101 long long find_shortcut(int n, std::vector<int> l,
102 std::vector<int> d, int c)
103 {
104 ::N = n; ::K = c;
105 for(int i = 1; i < N; i++) ::X[i] = ::X[i-1] + l[i-1];
106 for(int i = 0; i < N; i++) ::L[i] = d[i];
107 return getAns();
108 }
109
110 // BEGIN CUT
111 int main()
112 {
113 auto t1 = clock();
114
115 std::freopen("../tests/subtask_8/220", "r", stdin);
116 std::freopen("8-220.out.txt", "w", stdout);
117
118 int n, c;
119 scanf("%d%d", &n, &c);
120
121 vector<int> l(n - 1);
122 vector<int> d(n);
123 for (int i = 0; i < n - 1; i++)
124 scanf("%d", &l[i]);
125 for (int i = 0; i < n; i++)
126 scanf("%d", &d[i]);
127
128 auto t2 = clock();
129
130 long long t = find_shortcut(n, l, d, c);
131
132 auto t3 = clock();
133
134 // BEGIN SECRET
135 puts("14e047d7a2907b9034950b074822b302");
136 // END SECRET
137
138 printf("%lld\n", t);
139
140 auto t4 = clock();
141
142 // reset console output
143 freopen("CON", "w", stdout);
144
145 cout<<"n = "<<n<<" c = "<<c<<"\n";
146 cout<<"t = "<<t<<"\n\n";
147
148 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
149 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
150 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
151
152 return 0;
153 }
154 // END CUT
155 /*
CAPITOLUL 5. IOI 2016 590
63 {
64 int ind = dif[l++].se; // add element to set of elements
65 // producing the intersection
66
67 if (x[ind] - d[ind] < di)//lef.fi - lef.se)
68 di = x[ind] - d[ind];//lef = {x[ind], d[ind]};
69
70 if (x[ind] + d[ind] > sm)//rig.fi + rig.se)
71 sm = x[ind] + d[ind];//rig = {x[ind], d[ind]};
72 skip = true;
73 }
74
75 if (skip)
76 {
77 mxsm = min(mxsm, di + x[i] - d[i] + len - c);
78 mism = max(mism, sm + x[i] + d[i] - len + c);
79 mxdi = min(mxdi, x[i] - d[i] - sm + len - c);
80 midi = max(midi, x[i] + d[i] - di - len + c);
81 }
82
83 // current station dominates last used station -> remove
84 // 1. cur elem (i) dominates prev (j) -> xi-di < xj-dj
85 // 2. prev elem (i) dominates cur (j) -> xi+di > xj+dj
86 // dominating elements have extremal sm and di -> inc di, dec sm
87 while (l < r && dif[r - 1].fi > x[i] - d[i])
88 r--;
89 dif[r++] = {x[i] - d[i], i};
90 }
91
92 if (mxsm < mism || mxdi < midi)
93 return false;
94
95 // check if there is a shortcut satisfying this bounds
96 int curdi = 0, cursm = n;
97 for (int i = 0; i < n; i++)
98 {
99 while (curdi < n && x[curdi] - x[i] < midi) // violates 4.
100 curdi++;
101
102 // all indices >= curdi satisfy 4.
103 while (cursm > 0 && x[cursm - 1] + x[i] >= mism) // violates 2.
104 cursm--;
105
106 // all indices >= cursm satisfy 2.
107 int cur = max(max(cursm, curdi), i + 1); // shortcut with
108 // next element / all other combinations are checked
109 if (cur < n && x[cur] + x[i] <= mxsm && x[cur] - x[i] <= mxdi)
110 return true;
111 }
112
113 return false;
114 }
115
116 ll find_shortcut(int n, vi l, vi d2, int c)
117 {
118 for (int i = 0; i < n; i++)
119 {
120 d[i] = d2[i];
121 if (i == 0)
122 x[i] = 0;
123 else
124 x[i] = x[i - 1] + l[i - 1];
125 }
126
127 ll lo = 0, hi = INF, ret = -1;
128 while (lo <= hi)
129 {
130 ll mi = (lo + hi) / 2;
131 if (solve(mi, n, c))
132 hi = mi - 1, ret = mi;
133 else
134 lo = mi + 1;
135 }
136
137 return ret;
138 }
CAPITOLUL 5. IOI 2016 592
139
140 // BEGIN CUT
141 int main()
142 {
143 auto t1 = clock();
144
145 std::freopen("../tests/subtask_8/220", "r", stdin);
146 std::freopen("8-220.out.txt", "w", stdout);
147
148 int n, c;
149 scanf("%d%d", &n, &c);
150
151 vector<int> l(n - 1);
152 vector<int> d(n);
153 for (int i = 0; i < n - 1; i++)
154 scanf("%d", &l[i]);
155 for (int i = 0; i < n; i++)
156 scanf("%d", &d[i]);
157
158 auto t2 = clock();
159
160 long long t = find_shortcut(n, l, d, c);
161
162 auto t3 = clock();
163
164 // BEGIN SECRET
165 puts("14e047d7a2907b9034950b074822b302");
166 // END SECRET
167
168 printf("%lld\n", t);
169
170 auto t4 = clock();
171
172 // reset console output
173 freopen("CON", "w", stdout);
174
175 cout<<"n = "<<n<<" c = "<<c<<"\n";
176 cout<<"t = "<<t<<"\n\n";
177
178 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
179 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
180 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
181
182 return 0;
183 }
184 // END CUT
185 /*
186 n = 1000000 c = 1000
187 t = 1000857674
188
189 t2-t1 = 3.507
190 t3-t2 = 6.25
191 t4-t3 = 0
192
193 Process returned 0 (0x0) execution time : 9.805 s
194 Press any key to continue.
195 */
16
17 using namespace std;
18
19 typedef long long ll;
20
21 const ll INF = 1e17 + 7;
22 const int MAXN = 1e6 + 5;
23
24 ll x[MAXN], d[MAXN];
25 int dif[MAXN];
26
27 /*
28 j>i -> xi-di, xi+di are known
29 z+y<=len+(xj-dj)+(xi-di) -> mxsm
30 z+y>=(xj+dj)+(xi+di)-len -> mism
31 z-y<=len+(xj-dj)-(xi+di) -> mxdi
32 z-y>=(xj+dj)-(xi-di)-len -> midi
33
34 shortest path has to contain shortcut:
35 (xj+dj) - (xi-di) > k -> calc with 2 pointers
36 */
37
38 bool solve(ll len, int n, ll c)
39 {
40 ll mxsm = INF, mism = -INF, mxdi = INF, midi = -INF;
41 ll di = INF, sm = -INF;
42 int l = 0, r = 0;
43 bool skip = false;
44
45 // calculate bounds
46 for (int i = 0; i < n; i++)
47 {
48 while (l < r && x[i] + d[i] - (x[dif[l]] - d[dif[l]]) > len)
49 {
50 int ind = dif[l++]; // add element to set of elements
51 // producing the intersection
52 if (x[ind] - d[ind] < di)
53 di = x[ind] - d[ind];
54 if (x[ind] + d[ind] > sm)
55 sm = x[ind] + d[ind];
56 skip = true;
57 }
58
59 if (skip)
60 {
61 mxsm = min(mxsm, di + x[i] - d[i] + len - c);
62 mism = max(mism, sm + x[i] + d[i] - len + c);
63 mxdi = min(mxdi, x[i] - d[i] - sm + len - c);
64 midi = max(midi, x[i] + d[i] - di - len + c);
65 }
66
67 // current station dominates last used station -> remove
68 // 1. cur elem (i) dominates prev (j) -> xi-di < xj-dj
69 // 2. prev elem (i) dominates cur (j) -> xi+di > xj+dj
70 // dominating elements have extremal sm and di -> inc di, dec sm
71
72 while (l < r && x[dif[r - 1]] - d[dif[r - 1]] > x[i] - d[i])
73 r--;
74 dif[r++] = i;
75 }
76
77 if (mxsm < mism || mxdi < midi)
78 return false;
79
80 // check if there is a shortcut satisfying this bounds
81 int curdi = 0, cursm = n;
82 for (int i = 0; i < n; i++)
83 {
84 while (curdi < n && x[curdi] - x[i] < midi) // violates 4.
85 curdi++;
86 // all indices >= curdi satisfy 4.
87 while (cursm > 0 && x[cursm - 1] + x[i] >= mism) // violates 2.
88 cursm--;
89 // all indices >= cursm satisfy 2.
90 int cur = max(max(cursm, curdi), i + 1); // shortcut with
91 // next element / all other combinations are checked
CAPITOLUL 5. IOI 2016 594
92 if (cur < n && x[cur] + x[i] <= mxsm && x[cur] - x[i] <= mxdi)
93 return true;
94 }
95
96 return false;
97 }
98
99 ll find_shortcut(int n, vi l, vi d2, int c)
100 {
101 for (int i = 0; i < n; i++)
102 {
103 d[i] = d2[i];
104 if (i == 0)
105 x[i] = 0;
106 else
107 x[i] = x[i - 1] + l[i - 1];
108 }
109
110 ll lo = 0, hi = INF, ret = -1;
111 while (lo <= hi)
112 {
113 ll mi = (lo + hi) / 2;
114 if (solve(mi, n, c))
115 hi = mi - 1, ret = mi;
116 else
117 lo = mi + 1;
118 }
119
120 return ret;
121 }
122
123 // BEGIN CUT
124 int main()
125 {
126 auto t1 = clock();
127
128 std::freopen("../tests/subtask_8/220", "r", stdin);
129 std::freopen("8-220.out.txt", "w", stdout);
130
131 int n, c;
132 scanf("%d%d", &n, &c);
133
134 vector<int> l(n - 1);
135 vector<int> d(n);
136 for (int i = 0; i < n - 1; i++)
137 scanf("%d", &l[i]);
138 for (int i = 0; i < n; i++)
139 scanf("%d", &d[i]);
140
141 auto t2 = clock();
142
143 long long t = find_shortcut(n, l, d, c);
144
145 auto t3 = clock();
146
147 // BEGIN SECRET
148 puts("14e047d7a2907b9034950b074822b302");
149 // END SECRET
150
151 printf("%lld\n", t);
152
153 auto t4 = clock();
154
155 // reset console output
156 freopen("CON", "w", stdout);
157
158 cout<<"n = "<<n<<" c = "<<c<<"\n";
159 cout<<"t = "<<t<<"\n\n";
160
161 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
162 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
163 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
164
165 return 0;
166 }
167 // END CUT
CAPITOLUL 5. IOI 2016 595
168 /*
169 n = 1000000 c = 1000
170 t = 1000857674
171
172 t2-t1 = 3.886
173 t3-t2 = 2.516
174 t4-t3 = 0
175
176 Process returned 0 (0x0) execution time : 6.449 s
177 Press any key to continue.
178 */
62
63 return lo+1;
64 }
65
66 // BEGIN CUT
67 int main()
68 {
69 auto t1 = clock();
70
71 std::freopen("../tests/subtask_8/220", "r", stdin);
72 std::freopen("8-220.out.txt", "w", stdout);
73
74 int n, c;
75 scanf("%d%d", &n, &c);
76
77 vector<int> l(n - 1);
78 vector<int> d(n);
79 for (int i = 0; i < n - 1; i++)
80 scanf("%d", &l[i]);
81 for (int i = 0; i < n; i++)
82 scanf("%d", &d[i]);
83
84 auto t2 = clock();
85
86 long long t = find_shortcut(n, l, d, c);
87
88 auto t3 = clock();
89
90 // BEGIN SECRET
91 puts("14e047d7a2907b9034950b074822b302");
92 // END SECRET
93
94 printf("%lld\n", t);
95
96 auto t4 = clock();
97
98 // reset console output
99 freopen("CON", "w", stdout);
100
101 cout<<"n = "<<n<<" c = "<<c<<"\n";
102 cout<<"t = "<<t<<"\n\n";
103
104 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
105 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
106 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
107
108 return 0;
109 }
110 // END CUT
111 /*
112 n = 1000000 c = 1000
113 t = 1000857674
114
115 t2-t1 = 3.507
116 t3-t2 = 5.25
117 t4-t3 = 0
118
119 Process returned 0 (0x0) execution time : 8.804 s
120 Press any key to continue.
121 */
89 // BEGIN CUT
90 int main()
91 {
92 auto t1 = clock();
93
94 std::freopen("../tests/subtask_8/220", "r", stdin);
95 std::freopen("8-220.out.txt", "w", stdout);
96
97 int n, c;
98 scanf("%d%d", &n, &c);
99
100 vector<int> l(n - 1);
101 vector<int> d(n);
102 for (int i = 0; i < n - 1; i++)
103 scanf("%d", &l[i]);
104 for (int i = 0; i < n; i++)
105 scanf("%d", &d[i]);
106
107 auto t2 = clock();
108
109 long long t = find_shortcut(n, l, d, c);
110
111 auto t3 = clock();
112
113 // BEGIN SECRET
114 puts("14e047d7a2907b9034950b074822b302");
115 // END SECRET
116
117 printf("%lld\n", t);
118
119 auto t4 = clock();
120
121 // reset console output
122 freopen("CON", "w", stdout);
123
124 cout<<"n = "<<n<<" c = "<<c<<"\n";
125 cout<<"t = "<<t<<"\n\n";
126
127 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
128 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
129 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
130
131 return 0;
132 }
133 // END CUT
134 /*
135 n = 1000000 c = 1000
136 t = 1000857674
137
138 t2-t1 = 3.64
139 t3-t2 = 4.953
140 t4-t3 = 0
141
142 Process returned 0 (0x0) execution time : 8.625 s
143 Press any key to continue.
144 */
17 long long C;
18
19 bool check(long long k)
20 {
21 long long mxsum=-inf,mndif=inf;
22 long long suml=-inf,sumr=inf,difl=-inf,difr=inf;
23 long long sum,dif;
24 int p=1,u=0;
25 for(i=1;i<=n;i++)
26 {
27 while(p<=u&&x[i]-x[d[p]]+y[i]+y[d[p]]>k)
28 {
29 sum=x[d[p]]+y[d[p]];dif=x[d[p]]-y[d[p]];
30 if(sum>mxsum) mxsum=sum;
31 if(dif<mndif) mndif=dif;
32 p++;
33 }
34 if(mxsum!=-inf)
35 {
36 suml=max(suml,-k+C+mxsum+x[i]+y[i]);
37 sumr=min(sumr,k-C+mndif+x[i]-y[i]);
38 difl=max(difl,-k+C-mndif+x[i]+y[i]);
39 difr=min(difr,k-C-mxsum+x[i]-y[i]);
40 }
41 while(p<=u&&x[i]-y[i]<x[d[u]]-y[d[u]])
42 u--;
43 d[++u]=i;
44 }
45
46 if(suml>sumr||difl>difr) return 0;
47 int p1=1,p2=n;
48 int poz;
49 for(i=1;i<=n;i++)
50 {
51 while(p1<=n&&x[p1]-x[i]<difl)
52 p1++;
53 while(p2>=1&&x[p2]+x[i]>=suml)
54 p2--;
55 poz=max(i+1,max(p1,p2+1));
56 if(poz<=n&&
57 x[poz]+x[i]>=suml&&
58 x[poz]+x[i]<=sumr&&
59 x[poz]-x[i]>=difl&&
60 x[poz]-x[i]<=difr)
61 return 1;
62 }
63 return 0;
64 }
65
66 long long find_shortcut(int N, std::vector<int> l,
67 std::vector<int> d, int c)
68 {
69 C=c;n=N;
70 for(i=0;i<n-1;i++)
71 x[i+2]=x[i+1]+l[i];
72 for(i=0;i<n;i++)
73 y[i+1]=d[i];
74
75 long long ans=0;
76 for(long long p=50;p>=0;p--)
77 ans+=(1LL<<p);
78 for(long long p=50;p>=0;p--)
79 if(check(ans-(1LL<<p)))
80 ans-=(1LL<<p);
81
82 return ans;
83 }
84
85 // BEGIN CUT
86 int main()
87 {
88 auto t1 = clock();
89
90 std::freopen("../tests/subtask_8/220", "r", stdin);
91 std::freopen("8-220.out.txt", "w", stdout);
92
CAPITOLUL 5. IOI 2016 600
93 int n, c;
94 scanf("%d%d", &n, &c);
95
96 vector<int> l(n - 1);
97 vector<int> d(n);
98 for (int i = 0; i < n - 1; i++)
99 scanf("%d", &l[i]);
100 for (int i = 0; i < n; i++)
101 scanf("%d", &d[i]);
102
103 auto t2 = clock();
104
105 long long t = find_shortcut(n, l, d, c);
106
107 auto t3 = clock();
108
109 // BEGIN SECRET
110 puts("14e047d7a2907b9034950b074822b302");
111 // END SECRET
112
113 printf("%lld\n", t);
114
115 auto t4 = clock();
116
117 // reset console output
118 freopen("CON", "w", stdout);
119
120 cout<<"n = "<<n<<" c = "<<c<<"\n";
121 cout<<"t = "<<t<<"\n\n";
122
123 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
124 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
125 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
126
127 return 0;
128 }
129 // END CUT
130 /*
131 n = 1000000 c = 1000
132 t = 1000857674
133
134 t2-t1 = 3.562
135 t3-t2 = 4.498
136 t4-t3 = 0
137
138 Process returned 0 (0x0) execution time : 8.123 s
139 Press any key to continue.
140 */
25 bool is_valid(lint T)
26 {
27 lint max_sum = +INF; // maximum of S1 + S2 that is valid
28 lint min_sum = -INF; // minimum of S1 + S2 that is valid
29 lint max_dif = +INF; // maximum of S1 - S2 that is valid
30 lint min_dif = -INF; // minimum of S1 - S2 that is valid
31
32 lint sum_big = -INF; // maximum X[i] + D[i], for all valid i
33 lint sum_sml = -INF; // second maximum X[i] + D[i], for all valid i
34 int sum_idx = -1; // index of sum_big
35
36 lint dif_sml = +INF; // minimum X[i] - D[i], for all valid i
37 lint dif_big = +INF; // second minimum X[i] - D[i], for all valid i
38 int dif_idx = -1; // index of dif_sml
39
40 for (int j = 0, pos = 0; j < N; j++)
41 {
42 while (pos < N && SUM[j].sum - DIF[pos].dif > T)
43 {
44 lint sum_val = DIF[pos].sum, dif_val = DIF[pos].dif;
45
46 if (sum_big < sum_val)
47 {
48 sum_sml = sum_big;
49 sum_big = sum_val;
50 sum_idx = DIF[pos].id;
51 }
52 else
53 if (sum_sml < sum_val)
54 {
55 sum_sml = sum_val;
56 }
57
58 if (dif_sml > dif_val)
59 {
60 dif_big = dif_sml;
61 dif_sml = dif_val;
62 dif_idx = DIF[pos].id;
63 }
64 else
65 if (dif_big > dif_val)
66 {
67 dif_big = dif_val;
68 }
69
70 pos++;
71 }
72
73 lint valid_sum = ((SUM[j].id != sum_idx)? sum_big : sum_sml);
74 lint valid_dif = ((SUM[j].id != dif_idx)? dif_sml : dif_big);
75 lint sum_val = SUM[j].sum, dif_val = SUM[j].dif;
76
77 max_sum = min(max_sum, + T + valid_dif + dif_val - C);
78 min_sum = max(min_sum, - T + valid_sum + sum_val + C);
79 max_dif = min(max_dif, + T + valid_dif - sum_val - C);
80 min_dif = max(min_dif, - T + valid_sum - dif_val + C);
81 }
82
83 if (min_sum > max_sum || min_dif > max_dif)
84 return false;
85
86 for (int i = 0, ptl = 0, ptr = N - 1, pos; i < N; i++)
87 {
88 while (ptl < N && X[ptl] - X[i] < min_dif) ptl++;
89 while (ptr >= 0 && X[ptr] + X[i] >= min_sum) ptr--;
90
91 pos = max(ptl, ptr + 1);
92 if (pos < N &&
93 min_sum <= X[pos] + X[i] &&
94 X[pos] + X[i] <= max_sum &&
95 min_dif <= X[pos] - X[i] &&
96 X[pos] - X[i] <= max_dif)
97 return true;
98 }
99
100 return false;
CAPITOLUL 5. IOI 2016 602
101 }
102
103 lint find_shortcut(int n_, vector<int> l_, vector<int> D, int c_)
104 {
105 N = n_, C = c_;
106 for (int i = 0; i < l_.size(); i++)
107 X[i + 1] = X[i] + l_[i];
108 for (int i = 0; i < N; i++)
109 {
110 SUM[i] = SumDif{X[i] + D[i], X[i] - D[i], X[i], D[i], i};
111 DIF[i] = SumDif{X[i] + D[i], X[i] - D[i], X[i], D[i], i};
112 }
113
114 sort(SUM, SUM + N, [&](SumDif &l, SumDif &r) {return l.sum < r.sum;});
115 sort(DIF, DIF + N, [&](SumDif &l, SumDif &r) {return l.dif < r.dif;});
116
117 lint res = 0;
118
119 for (lint L = 0, R = INF, M = (L + R) / 2; L <= R; M = (L + R) / 2)
120 if (is_valid(M))
121 R = M - 1, res = M;
122 else
123 L = M + 1;
124
125 return res;
126 }
127
128 // BEGIN CUT
129 int main()
130 {
131 auto t1 = clock();
132
133 std::freopen("../tests/subtask_8/220", "r", stdin);
134 std::freopen("8-220.out.txt", "w", stdout);
135
136 int n, c;
137 scanf("%d%d", &n, &c);
138
139 vector<int> l(n - 1);
140 vector<int> d(n);
141 for (int i = 0; i < n - 1; i++)
142 scanf("%d", &l[i]);
143 for (int i = 0; i < n; i++)
144 scanf("%d", &d[i]);
145
146 auto t2 = clock();
147
148 long long t = find_shortcut(n, l, d, c);
149
150 auto t3 = clock();
151
152 // BEGIN SECRET
153 puts("14e047d7a2907b9034950b074822b302");
154 // END SECRET
155
156 printf("%lld\n", t);
157
158 auto t4 = clock();
159
160 // reset console output
161 freopen("CON", "w", stdout);
162
163 cout<<"n = "<<n<<" c = "<<c<<"\n";
164 cout<<"t = "<<t<<"\n\n";
165
166 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
167 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
168 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
169
170 return 0;
171 }
172 // END CUT
173 /*
174 n = 1000000 c = 1000
175 t = 1000857674
176
CAPITOLUL 5. IOI 2016 603
66 {
67 mins = max(mins, x[j] + d[j] + x[i] + d[i] - k + c);
68 maxs = min(maxs, k - c + (x[j] - d[j]) + x[i] - d[i]);
69 mind = max(mind, x[j] + d[j] - (x[i] - d[i]) - k + c);
70 maxd = min(maxd, k - c + (x[j] - d[j]) - (x[i] + d[i]));
71 }
72 }
73 }
74 }
75
76 return find_pair(mins, maxs, mind, maxd);
77 }
78
79 long long find_shortcut(int n, std::vector<int> l, std::vector<int> dd, int c)
80 {
81 d[1] = dd[0];
82 ::n = n;
83 ::c = c;
84 for(int i = 1 ; i < n ; i++)
85 {
86 x[i + 1] = x[i] + l[i - 1];
87 d[i + 1] = dd[i];
88 }
89
90 int max1 = 0, max2 = 0;
91 for(int i = 1 ; i <= n ; i++)
92 {
93 VP.emplace_back(x[i] + d[i], i);
94 VM.emplace_back(x[i] - d[i], i);
95 if(d[i] >= max1)
96 {
97 max2 = max1;
98 max1 = d[i];
99 }
100 else
101 if(d[i] > max2)
102 max2 = d[i];
103 }
104
105 sort(VP.begin(), VP.end());
106 sort(VM.begin(), VM.end());
107
108 ll a = max1 + max2, b = 1e18, mid;
109 while(a < b)
110 {
111 mid = (a + b) / 2;
112 if(check(mid))
113 b = mid;
114 else
115 a = mid + 1;
116 }
117
118 return a;
119 }
120
121 // BEGIN CUT
122 int main()
123 {
124 auto t1 = clock();
125
126 std::freopen("../tests/subtask_8/220", "r", stdin);
127 std::freopen("8-220.out.txt", "w", stdout);
128
129 int n, c;
130 scanf("%d%d", &n, &c);
131
132 vector<int> l(n - 1);
133 vector<int> d(n);
134 for (int i = 0; i < n - 1; i++)
135 scanf("%d", &l[i]);
136 for (int i = 0; i < n; i++)
137 scanf("%d", &d[i]);
138
139 auto t2 = clock();
140
141 long long t = find_shortcut(n, l, d, c);
CAPITOLUL 5. IOI 2016 605
142
143 auto t3 = clock();
144
145 // BEGIN SECRET
146 puts("14e047d7a2907b9034950b074822b302");
147 // END SECRET
148
149 printf("%lld\n", t);
150
151 auto t4 = clock();
152
153 // reset console output
154 freopen("CON", "w", stdout);
155
156 cout<<"n = "<<n<<" c = "<<c<<"\n";
157 cout<<"t = "<<t<<"\n\n";
158
159 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
160 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
161 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
162
163 return 0;
164 }
165 // END CUT
166 /*
167 n = 1000000 c = 1000
168 t = 1000857674
169
170 t2-t1 = 3.525
171 t3-t2 = 10.265
172 t4-t3 = 0
173
174 Process returned 0 (0x0) execution time : 13.853 s
175 Press any key to continue.
176 */
114 {
115 n = N;
116 c = C * 2;
117
118 ll mex = 0;
119
120 pf[0] = 0;
121
122 for (int i = 0; i < n - 1; i++)
123 //for (register int i = 0; i < n - 1; i++)
124 {
125 pf[i + 1] = pf[i] + l[i] * 2;
126 dst[i] = d[i] * 2;
127 mex = max(mex, dst[i]);
128 }
129
130 dst[n - 1] = d[n - 1] * 2;
131 mex = max(mex, dst[n - 1]);
132
133 for (int i = 0; i < n; i++)
134 //for (register int i = 0; i < n; i++)
135 {
136 events[i] = MP(-pf[i] - dst[i], i);
137 o_events[i]= MP(-pf[i] + dst[i], i);
138 }
139
140 sort(events, events + n);
141 sort(o_events, o_events + n);
142
143 seg_mx[0] = MP(-OO, -OO);
144 seg_mn[0] = MP(OO, OO);
145
146 for (int it = 1; it <= n; it++)
147 //for (register int it = 1; it <= n; it++)
148 {
149 int j = events[it - 1].sd;
150
151 pll nw = MP(pf[j] + dst[j], pf[j] - dst[j]);
152
153 seg_mx[it] = seg_mx[it - 1];
154 seg_mn[it] = seg_mn[it - 1];
155
156 if (seg_mx[it].ft < nw.ft){
157 swap(seg_mx[it].ft, seg_mx[it].sd);
158 seg_mx[it].ft = nw.ft;
159 } else if (seg_mx[it].sd < nw.ft)
160 seg_mx[it].sd = nw.ft;
161
162 if (seg_mn[it].ft > nw.sd){
163 swap(seg_mn[it].ft, seg_mn[it].sd);
164 seg_mn[it].ft = nw.sd;
165 } else if (seg_mn[it].sd > nw.sd)
166 seg_mn[it].sd = nw.sd;
167 }
168
169 // smth smaller
170 ll l1 = 0, r1 = mex + pf[n - 1] / 2;
171
172 while (l1 < r1){
173 ll md = (l1 + r1) >> 1;
174
175 if (ok(md * 2))
176 r1 = md;
177 else l1 = md + 1;
178 }
179
180 ok(16);
181
182 return l1;
183 }
184
185 // BEGIN CUT
186 int main()
187 {
188 auto t1 = clock();
189
CAPITOLUL 5. IOI 2016 608
trebuie sa e egal cu ci . De exemplu , dac indiciile sunt c 3, 4, jocul rezolvat trebuie s aib
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 e negre ³i anumite celule trebuie s e 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 ):
’X’: 88,
’_’: 95,
’.’: 46,
’?’: 63.
’’XXX_XXXX__’’,
’’XXX__XXXX_’’,
’’XXX___XXXX’’,
’’_XXX_XXXX_’’,
CAPITOLUL 5. IOI 2016 610
’’_XXX__XXXX’’,
’’__XXX_XXXX’’.
Î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 e 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 .
Step 1: Compute prex 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 rst i clues and the rst 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 i there is no given black cell among
the rst 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 suxes 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:
The above solution can conveniently be implemented in O nk , where k is the number of clues.
2
Less ecient 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 dierent 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 rst 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 rst j 1 black blocks from the
second solution and the remaining blocks from the rst solution.
CAPITOLUL 5. IOI 2016 612
This is a valid solution because in the second solution the rst j 1 black blocks are all strictly
to the left of cell x and in the rst 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.
139 {
140 if (ans[i] == 1) result[i] = ’_’;
141 else
142 if (ans[i] == 2) result[i] = ’X’;
143 else
144 if (ans[i] == 3) result[i] = ’?’;
145 else assert(0);
146 }
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");
CAPITOLUL 5. IOI 2016 615
47 {
48 sumB[i] += sumB[i - 1];
49 sumW[i] += sumW[i - 1];
50 }
51
52 if (it == 2) break;
53
54 dp[it][0][0] = 1;
55 for (int i = 1; i < n; i++)
56 {
57 for (int j = 0; j <= k; j++)
58 {
59 dp[it][i][j] |= dp[it][i-1][j] && (sumB[i]-sumB[i-1] == 0);
60 dp[it][i][j] |= j > 0 &&
61 i > C[j - 1] &&
62 sumW[i - 1] - sumW[i - C[j - 1] - 1] == 0 &&
63 sumB[i] - sumB[i - 1] == 0 &&
64 dp[it][i - C[j - 1] - 1][j - 1];
65 }
66 }
67
68 reverse(C.begin(), C.end());
69 reverse(B.begin(), B.end());
70 reverse(W.begin(), W.end());
71
72 for (int i = 0; i < (int)B.size(); i++) B[i] = n - B[i] - 1;
73 for (int i = 0; i < (int)W.size(); i++) W[i] = n - W[i] - 1;
74 }
75
76 reverse(dp[1].begin(), dp[1].end());
77 for (int i = 1; i < n - 1; i++)
78 {
79 for (int j = 0; j <= k; j++)
80 {
81 if (dp[0][i][j] && dp[1][i][k - j])
82 {
83 ans[i - 1] |= 1;
84 }
85 }
86 }
87
88 vector<int> a(n);
89 for (int i = 1; i < n; i++)
90 {
91 for (int j = 0; j <= k; j++)
92 {
93 if (j > 0 &&
94 i > C[j - 1] &&
95 sumW[i - 1] - sumW[i - C[j - 1] - 1] == 0 &&
96 sumB[i] - sumB[i - 1] == 0 &&
97 dp[0][i - C[j - 1] - 1][j - 1] &&
98 dp[1][i][k - j])
99 {
100 a[i - C[j - 1]]++;
101 a[i]--;
102 }
103 }
104 }
105
106 for (int i = 1; i < n; i++)
107 {
108 a[i] += a[i - 1];
109 if (a[i] > 0)
110 {
111 ans[i - 1] |= 2;
112 }
113 }
114
115 string res = "";
116 for (int i = 0; i < n - 2; i++)
117 {
118 if (ans[i] == 1) res += ’_’;
119 else if (ans[i] == 2) res += ’X’;
120 else if (ans[i] == 3) res += ’?’;
121 else assert(0);
122 }
CAPITOLUL 5. IOI 2016 617
123
124 return res;
125 }
126
127 // BEGIN CUT
128
129 const int S_MAX_LEN = 200 * 1000;
130 char buf[S_MAX_LEN + 1];
131
132 int main()
133 {
134 auto t1=clock();
135
136 //freopen("../tests/subtask_1/001", "r", stdin);
137 //freopen("1-001.out.txt", "w", stdout);
138
139 freopen("../tests/subtask_7/125", "r", stdin);
140 freopen("7-125.out.txt", "w", stdout);
141
142 scanf("%s", buf);
143 std::string s = buf;
144 int c_len;
145 scanf("%d", &c_len);
146 std::vector<int> c(c_len);
147 for (int i = 0; i < c_len; i++) {
148 scanf("%d", &c[i]);
149 }
150
151 auto t2=clock();
152
153 std::string ans = solve_puzzle(s, c);
154
155 auto t3=clock();
156
157 // BEGIN SECRET
158 //puts("098d134608c94f7413faac591054ee35");
159 // END SECRET
160
161 printf("%s\n", ans.data());
162
163 auto t4=clock();
164
165 // reset console output
166 freopen("CON", "w", stdout);
167
168 printf("t2-t1 = %f\n", (double)(t2 - t1) / CLOCKS_PER_SEC);
169 printf("t3-t2 = %f\n", (double)(t3 - t2) / CLOCKS_PER_SEC);
170 printf("t4-t3 = %f\n", (double)(t4 - t3) / CLOCKS_PER_SEC);
171
172 /*
173 printf("%s\n", s);
174 printf("%d ", k);
175 for (int i = 0; i < k; i++)
176 {
177 printf("%d ", c[i]);
178 }
179 printf("\n");
180 printf("%s\n", result);
181 */
182
183 return 0;
184 }
185 // END CUT
186 /*
187 t2-t1 = 0.015000
188 t3-t2 = 6.432000
189 t4-t3 = 0.016000
190
191 Process returned 0 (0x0) execution time : 6.541 s
192 Press any key to continue.
193
194 argc = 4
195 checker
196 ../tests/subtask_7/125
197 ../tests/subtask_7/125.a
198 7-125.out.txt
CAPITOLUL 5. IOI 2016 618
199 ----------------------
200 1
201 Correct
202
203 Process returned 0 (0x0) execution time : 0.078 s
204 Press any key to continue.
205 */
66
67 vector<int> B(L,0);
68 for (int i = 0; i < L; i++) B[i] = S[i] == ’X’;
69
70 vector<int> W(L,0);
71 for (int i = 0; i < L; i++) W[i] = S[i] == ’_’;
72
73 vector< vector<bool> > can_fit_prefix = get_possible_prefixes(C,B,W);
74
75 reverse( C.begin(), C.end() );
76 reverse( B.begin(), B.end() );
77 reverse( W.begin(), W.end() );
78
79 vector< vector<bool> > can_fit_suffix = get_possible_prefixes(C,B,W);
80
81 reverse( C.begin(), C.end() );
82 reverse( B.begin(), B.end() );
83 reverse( W.begin(), W.end() );
84
85 vector<bool> can_be_white(L,false);
86
87 for (int l=0; l<L; ++l)
88 for (int n=0; n<=N; ++n)
89 if (!B[l] &&
90 can_fit_prefix[l][n] &&
91 can_fit_suffix[L-l-1][N-n])
92 can_be_white[l] = true;
93
94 vector<int> Wsums(L+1,0);
95 for (int l=0; l<L; ++l)
96 Wsums[l+1]=Wsums[l]+W[l];
97
98 vector<int> intervals(L+1,0);
99
100 for (int n=0; n<N; ++n)
101 {
102 for (int start=0; start+C[n]<=L; ++start)
103 {
104 if (start > 0 && B[start-1]) continue;
105 if (start+C[n]<L && B[start+C[n]]) continue;
106 if (Wsums[start+C[n]] > Wsums[start]) continue;
107 if (can_fit_prefix[max(0,start-1)][n] &&
108 can_fit_suffix[max(0,L-start-C[n]-1)][N-n-1])
109 {
110 intervals[start] += 1;
111 intervals[start+C[n]] -= 1;
112 }
113 }
114 }
115
116 vector<bool> can_be_black(L+1,false);
117
118 int inside = 0;
119 for (int l=0; l<L; ++l)
120 {
121 inside += intervals[l];
122 if (inside > 0) can_be_black[l] = true;
123 }
124
125 std::string ans;
126 for (int l=0; l<L; ++l)
127 {
128 if (can_be_black[l] && can_be_white[l]) ans.push_back(’?’);
129 if (can_be_black[l] && !can_be_white[l]) ans.push_back(’X’);
130 if (!can_be_black[l] && can_be_white[l]) ans.push_back(’_’);
131 if (!can_be_black[l] && !can_be_white[l]) ans.push_back(’!’);
132 }
133
134 return ans;
135 }
136
137 const int S_MAX_LEN = 200 * 1000;
138 char buf[S_MAX_LEN + 1];
139
140 // BEGIN CUT
141
CAPITOLUL 5. IOI 2016 620
1 #include "testlib.h"
2
3 #include<iostream>
4
5 using namespace std;
6
7 const string output_secret = "098d134608c94f7413faac591054ee35";
8
9 int main()
10 {
11 int argc=4;
12
13 char* argv[] =
14 {
15 (char*)"checker",
16 (char*)"../tests/subtask_7/125", // input
17 (char*)"../tests/subtask_7/125.a", // rezultat corect
18 (char*)"7-125.out.txt", // rezultat de verificat
19 };
20
21 cout<<"argc = "<<argc<<"\n";
22 for(int kk=0;kk<argc;kk++)
23 cout<<argv[kk]<<"\n";
24 cout<<"----------------------\n";
25
26 registerChecker("paint", argc, argv);
27
28 //readBothSecrets(output_secret);
29 //readBothGraderResults();
30 //compareRemainingLines(3); // incepand cu linia nr 3
31
32 compareRemainingLines(1); // incepand cu linia nr 1
33 }
40 {
41 if (j < m &&
42 i + c[j] <= n + 1 &&
43 a[i - 1] == a[i + c[j] - 1] &&
44 (j + 1 == m ? R[i + c[j]][j + 1] : i + c[j] < n + 1 &&
45 R[i + c[j] + 1][j + 1] &&
46 s[i + c[j] - 1] != ’X’))
47 {
48 R[i][j] = true;
49 if (j ? i > 1 && L[i-2][j] && s[i-2] != ’X’ : L[i-1][0])
50 {
51 yes[i - 1]++;
52 yes[i + c[j] - 1]--;
53 }
54 continue;
55 }
56 if (s[i - 1] != ’X’ && R[i + 1][j])
57 R[i][j] = true;
58 }
59 std::string res;
60 for (i = 0; i < n; i++)
61 {
62 yes[i + 1] += yes[i];
63 if (s[i] != ’X’)
64 {
65 for (j = 0; j <= m; j++)
66 if (L[i][j] && R[i + 2][j])
67 break;
68 no[i] = j <= m;
69 }
70 res.push_back(yes[i] && no[i] ? ’?’ : yes[i] ? ’X’ : ’_’);
71 }
72
73 return res;
74 }
75
76 // BEGIN CUT
77
78 const int S_MAX_LEN = 200 * 1000;
79 char buf[S_MAX_LEN + 1];
80
81 int main()
82 {
83 auto t1=clock();
84
85 freopen("../tests/subtask_7/125", "r", stdin);
86 freopen("7-125.out.txt", "w", stdout);
87
88 scanf("%s", buf);
89 std::string s = buf;
90 int c_len;
91 scanf("%d", &c_len);
92 std::vector<int> c(c_len);
93 for (int i = 0; i < c_len; i++)
94 {
95 scanf("%d", &c[i]);
96 }
97
98 auto t2=clock();
99
100 std::string ans = solve_puzzle(s, c);
101
102 auto t3=clock();
103
104 printf("%s\n", ans.data());
105
106 auto t4=clock();
107
108 // reset console output
109 freopen("CON", "w", stdout);
110
111 printf("t2-t1 = %f\n", (double)(t2 - t1) / CLOCKS_PER_SEC);
112 printf("t3-t2 = %f\n", (double)(t3 - t2) / CLOCKS_PER_SEC);
113 printf("t4-t3 = %f\n", (double)(t4 - t3) / CLOCKS_PER_SEC);
114
115 return 0;
CAPITOLUL 5. IOI 2016 623
116 }
117 // END CUT
118 /*
119 t2-t1 = 0.031000
120 t3-t2 = 1.594000
121 t4-t3 = 0.015000
122
123 Process returned 0 (0x0) execution time : 1.750 s
124 Press any key to continue.
125 */
63 if (pb[i][j])
64 {
65 bqs[i] += 1;
66 bqs[i+c[j]] -= 1;
67 wqs[i+c[j]] = 1;
68 reach[min(n+1, i+c[j]+1)][j+1] = true;
69 }
70 if (pw[i][j])
71 {
72 wqs[i] = 1;
73 reach[i+1][j] = true;
74 }
75 }
76 }
77
78 string ans(n, ’\0’);
79 for (int i = 1; i <= n; ++i)
80 {
81 bqs[i] += bqs[i-1];
82 if (wqs[i] && bqs[i]) ans[i-1] = both;
83 else
84 if (wqs[i]) ans[i-1] = white;
85 else ans[i-1] = black;
86 }
87
88 return ans;
89 }
90
91 // BEGIN CUT
92
93 const int S_MAX_LEN = 200 * 1000;
94 char buf[S_MAX_LEN + 1];
95
96 int main()
97 {
98 auto t1=clock();
99
100 freopen("../tests/subtask_7/125", "r", stdin);
101 freopen("7-125.out.txt", "w", stdout);
102
103 scanf("%s", buf);
104 std::string s = buf;
105 int c_len;
106 scanf("%d", &c_len);
107 std::vector<int> c(c_len);
108 for (int i = 0; i < c_len; i++)
109 {
110 scanf("%d", &c[i]);
111 }
112
113 auto t2=clock();
114
115 std::string ans = solve_puzzle(s, c);
116
117 auto t3=clock();
118
119 printf("%s\n", ans.data());
120
121 auto t4=clock();
122
123 // reset console output
124 freopen("CON", "w", stdout);
125
126 printf("t2-t1 = %f\n", (double)(t2 - t1) / CLOCKS_PER_SEC);
127 printf("t3-t2 = %f\n", (double)(t3 - t2) / CLOCKS_PER_SEC);
128 printf("t4-t3 = %f\n", (double)(t4 - t3) / CLOCKS_PER_SEC);
129
130 return 0;
131 }
132 // END CUT
133 /*
134 t2-t1 = 0.015000
135 t3-t2 = 1.781000
136 t4-t3 = 0.016000
137
138 Process returned 0 (0x0) execution time : 2.016 s
CAPITOLUL 5. IOI 2016 625
71 return ret;
72 }
73
74 std::string solve_puzzle(std::string s, std::vector<int> c)
75 {
76 ::N = s.length(); ::K = c.size();
77 for(int i = 0; i < ::N; i++) ::A[i+1] = s[i];
78 for(int i = 0; i < ::K; i++) ::B[i+1] = c[i];
79 return getAns();
80 }
81
82 // BEGIN CUT
83
84 const int S_MAX_LEN = 200 * 1000;
85 char buf[S_MAX_LEN + 1];
86
87 int main()
88 {
89 auto t1=clock();
90
91 freopen("../tests/subtask_7/125", "r", stdin);
92 freopen("7-125.out.txt", "w", stdout);
93
94 scanf("%s", buf);
95 std::string s = buf;
96 int c_len;
97 scanf("%d", &c_len);
98 std::vector<int> c(c_len);
99 for (int i = 0; i < c_len; i++)
100 {
101 scanf("%d", &c[i]);
102 }
103
104 auto t2=clock();
105
106 std::string ans = solve_puzzle(s, c);
107
108 auto t3=clock();
109
110 printf("%s\n", ans.data());
111
112 auto t4=clock();
113
114 // reset console output
115 freopen("CON", "w", stdout);
116
117 printf("t2-t1 = %f\n", (double)(t2 - t1) / CLOCKS_PER_SEC);
118 printf("t3-t2 = %f\n", (double)(t3 - t2) / CLOCKS_PER_SEC);
119 printf("t4-t3 = %f\n", (double)(t4 - t3) / CLOCKS_PER_SEC);
120
121 return 0;
122 }
123 // END CUT
124 /*
125 t2-t1 = 0.031000
126 t3-t2 = 11.633000
127 t4-t3 = 0.016000
128
129 Process returned 0 (0x0) execution time : 11.727 s
130 Press any key to continue.
131 */
12 {
13
14 n = s.size(), k = _c.size();
15 copy(_c.begin(), _c.end(), c + 1);
16 s = "." + s + ".";
17
18 for(int i = 1; i <= n; ++i)
19 {
20 black[i] = black[i - 1] + (s[i] == ’X’);
21 white[i] = white[i - 1] + (s[i] == ’_’);
22 }
23 white[n + 1] = white[n];
24
25
26 f[0][0] = 1;
27 for(int i = 1; i <= n; ++i)
28 {
29 f[i][0] = black[i] == 0;
30 for(int j = 1; j <= k; ++j)
31 {
32 bool w = f[i - 1][j];
33 bool b = (i >= c[j]) &&
34 (s[i - c[j]] != ’X’) &&
35 (white[i] == white[i - c[j]])&&
36 (i > c[j] ? f[i - c[j] - 1][j - 1] : (j == 1));
37
38 f[i][j] = s[i] == ’_’ ? w : s[i] == ’X’ ? b : (w | b);
39 }
40 }
41
42 g[n + 1][k + 1] = g[n + 2][k + 1] = 1;
43 for(int i = n; i >= 1; --i)
44 {
45 g[i][k + 1] = black[n] == black[i - 1];
46 for(int j = k; j >= 1; --j)
47 {
48 bool w = g[i + 1][j];
49 bool b = (n - i + 1 >= c[j]) &&
50 (s[i + c[j]] != ’X’) &&
51 (white[i - 1] == white[i + c[j] - 1]) &&
52 g[i + c[j] + 1][j + 1];
53
54 g[i][j] = s[i] == ’_’ ? w : s[i] == ’X’ ? b : (w | b);
55 }
56 }
57
58 for(int i = 1; i <= n; ++i)
59 {
60 if(s[i] == ’_’) can_w[i] = 1;
61 else
62 {
63 for(int c = 0; c <= k && !can_w[i]; ++c)
64 {
65 can_w[i] |= f[i - 1][c] && g[i + 1][c + 1];
66 }
67 }
68
69 for(int j = 1; j <= k; ++j)
70 {
71 if(i >= c[j] &&
72 s[i - c[j]] != ’X’ &&
73 s[i + 1] != ’X’ &&
74 white[i] == white[i - c[j]] &&
75 (i > c[j] ? f[i - c[j] - 1][j - 1] : (j == 1)) &&
76 g[i + 2][j + 1])
77 {
78 t[i - c[j] + 1]++; t[i + 1]--;
79 }
80 }
81 }
82
83 for(int i = 1; i <= n; ++i)
84 {
85 t[i] += t[i - 1];
86 can_b[i] = t[i] > 0;
87 }
CAPITOLUL 5. IOI 2016 628
88
89 string ans = "";
90 for(int i = 1; i <= n; ++i)
91 {
92 if(s[i] != ’.’) ans += s[i];
93 else
94 {
95 if(can_w[i] && can_b[i]) ans += ’?’;
96 else ans += (can_w[i] ? ’_’ : ’X’);
97 }
98 }
99
100 return ans;
101 }
102
103 // BEGIN CUT
104
105 const int S_MAX_LEN = 200 * 1000;
106 char buf[S_MAX_LEN + 1];
107
108 int main()
109 {
110 auto t1=clock();
111
112 freopen("../tests/subtask_7/125", "r", stdin);
113 freopen("7-125.out.txt", "w", stdout);
114
115 scanf("%s", buf);
116 std::string s = buf;
117 int c_len;
118 scanf("%d", &c_len);
119 std::vector<int> c(c_len);
120 for (int i = 0; i < c_len; i++)
121 {
122 scanf("%d", &c[i]);
123 }
124
125 auto t2=clock();
126
127 std::string ans = solve_puzzle(s, c);
128
129 auto t3=clock();
130
131 printf("%s\n", ans.data());
132
133 auto t4=clock();
134
135 // reset console output
136 freopen("CON", "w", stdout);
137
138 printf("t2-t1 = %f\n", (double)(t2 - t1) / CLOCKS_PER_SEC);
139 printf("t3-t2 = %f\n", (double)(t3 - t2) / CLOCKS_PER_SEC);
140 printf("t4-t3 = %f\n", (double)(t4 - t3) / CLOCKS_PER_SEC);
141
142 return 0;
143 }
144 // END CUT
145 /*
146 t2-t1 = 0.015000
147 t3-t2 = 2.203000
148 t4-t3 = 0.016000
149
150 Process returned 0 (0x0) execution time : 2.422 s
151 Press any key to continue.
152 */
84
85 return ans;
86 }
87
88 // BEGIN CUT
89
90 const int S_MAX_LEN = 200 * 1000;
91 char buf[S_MAX_LEN + 1];
92
93 int main()
94 {
95 auto t1=clock();
96
97 freopen("../tests/subtask_7/125", "r", stdin);
98 freopen("7-125.out.txt", "w", stdout);
99
100 scanf("%s", buf);
101 std::string s = buf;
102 int c_len;
103 scanf("%d", &c_len);
104 std::vector<int> c(c_len);
105 for (int i = 0; i < c_len; i++)
106 {
107 scanf("%d", &c[i]);
108 }
109
110 auto t2=clock();
111
112 std::string ans = solve_puzzle(s, c);
113
114 auto t3=clock();
115
116 printf("%s\n", ans.data());
117
118 auto t4=clock();
119
120 // reset console output
121 freopen("CON", "w", stdout);
122
123 printf("t2-t1 = %f\n", (double)(t2 - t1) / CLOCKS_PER_SEC);
124 printf("t3-t2 = %f\n", (double)(t3 - t2) / CLOCKS_PER_SEC);
125 printf("t4-t3 = %f\n", (double)(t4 - t3) / CLOCKS_PER_SEC);
126
127 return 0;
128 }
129 // END CUT
130 /*
131 t2-t1 = 0.015000
132 t3-t2 = 3.141000
133 t4-t3 = 0.015000
134
135 Process returned 0 (0x0) execution time : 3.219 s
136 Press any key to continue.
137 */
95 auto t1=clock();
96
97 freopen("../tests/subtask_7/125", "r", stdin);
98 freopen("7-125.out.txt", "w", stdout);
99
100 scanf("%s", buf);
101 std::string s = buf;
102 int c_len;
103 scanf("%d", &c_len);
104 std::vector<int> c(c_len);
105 for (int i = 0; i < c_len; i++)
106 {
107 scanf("%d", &c[i]);
108 }
109
110 auto t2=clock();
111
112 std::string ans = solve_puzzle(s, c);
113
114 auto t3=clock();
115
116 printf("%s\n", ans.data());
117
118 auto t4=clock();
119
120 // reset console output
121 freopen("CON", "w", stdout);
122
123 printf("t2-t1 = %f\n", (double)(t2 - t1) / CLOCKS_PER_SEC);
124 printf("t3-t2 = %f\n", (double)(t3 - t2) / CLOCKS_PER_SEC);
125 printf("t4-t3 = %f\n", (double)(t4 - t3) / CLOCKS_PER_SEC);
126
127 return 0;
128 }
129 // END CUT
130 /*
131 t2-t1 = 0.015000
132 t3-t2 = 2.855000
133 t4-t3 = 0.016000
134
135 Process returned 0 (0x0) execution time : 2.949 s
136 Press any key to continue.
137 */
53 while(true)
54 {
55 if(state[i+1][r])
56 {
57 if(r-l <= sz[i+1]) state[i][l--] = false;
58 else
59 if(state[i][l])
60 {
61 if(prefX[r-sz[i+1]] - prefX[l] == 0)
62 canX[l-sz[i]+1]++,
63 canX[l+1]--,
64 can_[l+1]++,
65 can_[r-sz[i+1]+1]--,
66 l--;
67 else r--;
68 }
69 else l--;
70 }
71 else r--;
72
73 if(l < 0 || r < 0) break;
74 }
75
76 for(int j = l; j >= 0; --j)
77 state[i][j] = false;
78 }
79 }
80
81 for(int j = 2; j <= n+1; ++j)
82 canX[j] += canX[j-1], can_[j] += can_[j-1];
83
84 string str;
85 for(int j = 2; j <= n+1; ++j)
86 {
87 if(canX[j] && can_[j]) str.push_back(’?’);
88 else
89 if(canX[j]) str.push_back(’X’);
90 else str.push_back(’_’);
91 }
92
93 return str;
94 }
95
96 // BEGIN CUT
97
98 const int S_MAX_LEN = 200 * 1000;
99 char buf[S_MAX_LEN + 1];
100
101 int main()
102 {
103 auto t1=clock();
104
105 freopen("../tests/subtask_7/125", "r", stdin);
106 freopen("7-125.out.txt", "w", stdout);
107
108 scanf("%s", buf);
109 std::string s = buf;
110 int c_len;
111 scanf("%d", &c_len);
112 std::vector<int> c(c_len);
113 for (int i = 0; i < c_len; i++)
114 {
115 scanf("%d", &c[i]);
116 }
117
118 auto t2=clock();
119
120 std::string ans = solve_puzzle(s, c);
121
122 auto t3=clock();
123
124 printf("%s\n", ans.data());
125
126 auto t4=clock();
127
128 // reset console output
CAPITOLUL 5. IOI 2016 636
56 {
57 A=s;
58 seg=c;
59 n=s.size();
60 k=c.size();
61 for(int i=n-1; i>=0; i--)
62 suf[i]=A[i]==’_’?0:1+suf[i+1];
63
64 memset(dp, -1, sizeof(dp));
65
66 f(0, 0);
67 back(0, 0);
68
69 int st=0;
70 ans.resize(n);
71 for(int i=0; i<n; i++)
72 {
73 st+=isi[i];
74 if(emptyy[i] && st>0) ans[i]=’?’;
75 else
76 if(emptyy[i]) ans[i]=’_’;
77 else
78 if(st>0) ans[i]=’X’;
79 }
80 return ans;
81 }
82
83 // BEGIN CUT
84
85 const int S_MAX_LEN = 200 * 1000;
86 char buf[S_MAX_LEN + 1];
87
88 int main()
89 {
90 auto t1=clock();
91
92 freopen("../tests/subtask_7/125", "r", stdin);
93 freopen("7-125.out.txt", "w", stdout);
94
95 scanf("%s", buf);
96 std::string s = buf;
97 int c_len;
98 scanf("%d", &c_len);
99 std::vector<int> c(c_len);
100 for (int i = 0; i < c_len; i++)
101 {
102 scanf("%d", &c[i]);
103 }
104
105 auto t2=clock();
106
107 std::string ans = solve_puzzle(s, c);
108
109 auto t3=clock();
110
111 printf("%s\n", ans.data());
112
113 auto t4=clock();
114
115 // reset console output
116 freopen("CON", "w", stdout);
117
118 printf("t2-t1 = %f\n", (double)(t2 - t1) / CLOCKS_PER_SEC);
119 printf("t3-t2 = %f\n", (double)(t3 - t2) / CLOCKS_PER_SEC);
120 printf("t4-t3 = %f\n", (double)(t4 - t3) / CLOCKS_PER_SEC);
121
122 return 0;
123 }
124 // END CUT
125 /*
126 t2-t1 = 0.015000
127 t3-t2 = 0.125000
128 t4-t3 = 0.016000
129
130 Process returned 0 (0x0) execution time : 1.188 s
131 Press any key to continue.
CAPITOLUL 5. IOI 2016 638
132 */
72 {
73 Sol.push_back(’X’);
74 }
75 else
76 {
77 Sol.push_back(’_’);
78 }
79 }
80
81 return(Sol);
82 }
83
84 // BEGIN CUT
85
86 const int S_MAX_LEN = 200 * 1000;
87 char buf[S_MAX_LEN + 1];
88
89 int main()
90 {
91 auto t1=clock();
92
93 freopen("../tests/subtask_7/125", "r", stdin);
94 freopen("7-125.out.txt", "w", stdout);
95
96 scanf("%s", buf);
97 std::string s = buf;
98 int c_len;
99 scanf("%d", &c_len);
100 std::vector<int> c(c_len);
101 for (int i = 0; i < c_len; i++)
102 {
103 scanf("%d", &c[i]);
104 }
105
106 auto t2=clock();
107
108 std::string ans = solve_puzzle(s, c);
109
110 auto t3=clock();
111
112 printf("%s\n", ans.data());
113
114 auto t4=clock();
115
116 // reset console output
117 freopen("CON", "w", stdout);
118
119 printf("t2-t1 = %f\n", (double)(t2 - t1) / CLOCKS_PER_SEC);
120 printf("t3-t2 = %f\n", (double)(t3 - t2) / CLOCKS_PER_SEC);
121 printf("t4-t3 = %f\n", (double)(t4 - t3) / CLOCKS_PER_SEC);
122
123 return 0;
124 }
125 // END CUT
126 /*
127 t2-t1 = 0.015000
128 t3-t2 = 0.047000
129 t4-t3 = 0.016000
130
131 Process returned 0 (0x0) execution time : 0.125 s
132 Press any key to continue.
133 */
Ilshat este un programator care lucreaz la dezvoltarea unor structuri de date eciente. î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 .
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 nal, programul poate apela funcµia check_element(x)\verb pentru a verica dac
elementul este prezent în structura de date. Aceast funcµie poate 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 ec 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 ecare 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 ind cel mai semnicativ 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 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 verice prezenµa unor elemente din mulµimea modicat ,
5. s foloseasc informaµia primit pentru a determina ³i a întoarce permutarea .
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
"Wrong Answer".
Pentru toate stringurile, primul caracter denot cel mai semnicativ bit al întregului cores-
punz tor.
Grader-ul xeaz permutarea înainte ca funcµia restore_permutation s e apelat .
Folosiµi ³ierele template furnizate pentru detalii de implementare în limbajul vostru de pro-
gramare.
Exemple
Grader-ul face urm torul apel:
Sample grader
Sample grader-ul cite³te input-ul în urm torul format:
CAPITOLUL 5. IOI 2016 642
` 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 nd the position of bit 0.
This can be done using at most n 1 queries:
a Now we know the position of bit 0 and want to nd the position of bit 1. This can be done
using at most n 2 queries:
a And so on, we can nd 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 shue 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:
CAPITOLUL 5. IOI 2016 643
add_element("10000000")
add_element("01000000")
add_element("00100000")
add_element("00010000")
a After this, we will check n elements with single bit set to one. For example:
a Now we know, which n©2 bits correspond to rst 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 dierent 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")
27
28 //readBothSecrets(output_secret);
29 //readBothGraderResults();
30 //compareRemainingLines(3); // incepand cu linia nr 3
31
32 compareRemainingLines(1); // incepand cu linia nr 1
33 }
66 }
67 printf("\n");
68
69 auto t4 = clock();
70
71 // reset console output
72 freopen("CON", "w", stdout);
73
74 //cout<<"res = "<<res<<"\n";
75
76 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
77 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
78 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
79
80 return 0;
81 }
82
83 bool check(const string& x)
84 {
85 if (x.length() != n)
86 {
87 return false;
88 }
89 for (int i = 0; i < n; i++)
90 {
91 if (x[i] != ’0’ && x[i] != ’1’)
92 {
93 return false;
94 }
95 }
96 return true;
97 }
98
99 void add_element(string x)
100 {
101 if (--w < 0 || compiled || !check(x))
102 {
103 printf("WA\n");
104 exit(0);
105 }
106 set_.insert(x);
107 }
108
109 bool check_element(string x)
110 {
111 if (--r < 0 || !compiled || !check(x))
112 {
113 printf("WA\n");
114 exit(0);
115 }
116 return set_.count(x);
117 }
118
119 void compile_set()
120 {
121 if (compiled)
122 {
123 printf("WA\n");
124 exit(0);
125 }
126 compiled = true;
127 set<string> compiledSet;
128 string compiledElement = string(n, ’ ’);
129 for (const string& s : set_)
130 {
131 for (int i = 0; i < n; i++)
132 {
133 compiledElement[i] = s[p[i]];
134 }
135 compiledSet.insert(compiledElement);
136 }
137 set_ = compiledSet;
138 }
139
140 int nn;
141 string address;
CAPITOLUL 5. IOI 2016 646
142
143 void helper(int length, int w)
144 {
145 fill(address.begin(), address.end(), ’1’);
146 for (int i = w; i < nn; i += (1 << length))
147 {
148 address[i] = ’0’;
149 }
150 int j = w;
151 for (int i = 0; i < (nn / (1 << length)); i++)
152 {
153 address[j] = ’1’;
154 if (i % 2 == 1)
155 {
156 add_element(address);
157 }
158 address[j] = ’0’;
159 j += 1 << length;
160 }
161 }
162
163 void doWrites(int n_)
164 {
165 nn = n_;
166 address = string(nn, ’0’);
167 for (int i = 0; i < nn; i++)
168 {
169 fill(address.begin(), address.end(), ’0’);
170 address[i] = ’1’;
171 if (i % 2 == 1)
172 {
173 add_element(address);
174 }
175 }
176
177 int x = 1;
178 int log = 0;
179 while (x < nn)
180 {
181 x *= 2;
182 log++;
183 }
184 for (int length = 1; length < log; length++)
185 {
186 for (int i = 0; i < (1 << length); i++)
187 {
188 helper(length, i);
189 }
190 }
191 }
192
193 void read(const vector<int> &t, vector<int>& answer, int step, int w)
194 {
195 if (t.size() == 1)
196 {
197 answer[t[0]] = w;
198 return;
199 }
200 vector<int> t0;
201 vector<int> t1;
202 fill(address.begin(), address.end(), ’1’);
203 for (int j : t)
204 {
205 address[j] = ’0’;
206 }
207 for (int j : t)
208 {
209 address[j] = ’1’;
210 if (!check_element(address))
211 {
212 t0.push_back(j);
213 }
214 else
215 {
216 t1.push_back(j);
217 }
CAPITOLUL 5. IOI 2016 647
41
42 n = readInt();
43 w = readInt();
44 r = readInt();
45
46 p = vector<int>(n);
47
48 for (int i = 0; i < n; i++)
49 {
50 p[i] = readInt();
51 }
52
53 auto t2 = clock();
54
55 vector<int> answer = restore_permutation(n, w, r);
56
57 auto t3 = clock();
58
59 //printf("098d134608c94f7413faac591054ee35\n");
60 //if (p == answer) { printf("OK\n"); }
61 //else { printf("WA\n"); }
62
63 printf("%d", answer[0]);
64 for (int i = 1; i < n; i++)
65 {
66 printf(" %d", answer[i]);
67 }
68 printf("\n");
69
70 auto t4 = clock();
71
72 // reset console output
73 freopen("CON", "w", stdout);
74
75 //cout<<"res = "<<res<<"\n";
76
77 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
78 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
79 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
80
81 return 0;
82 }
83
84 bool check(const string& x)
85 {
86 if (x.length() != n)
87 {
88 return false;
89 }
90 for (int i = 0; i < n; i++)
91 {
92 if (x[i] != ’0’ && x[i] != ’1’)
93 {
94 return false;
95 }
96 }
97 return true;
98 }
99
100 void add_element(string x)
101 {
102 if (--w < 0 || compiled || !check(x))
103 {
104 printf("WA\n");
105 exit(0);
106 }
107 set_.insert(x);
108 }
109
110 bool check_element(string x)
111 {
112 if (--r < 0 || !compiled || !check(x))
113 {
114 printf("WA\n");
115 exit(0);
116 }
CAPITOLUL 5. IOI 2016 649
56
57 auto t3 = clock();
58
59 //printf("098d134608c94f7413faac591054ee35\n");
60 //if (p == answer) { printf("OK\n"); }
61 //else { printf("WA\n"); }
62
63 printf("%d", answer[0]);
64 for (int i = 1; i < n; i++)
65 {
66 printf(" %d", answer[i]);
67 }
68 printf("\n");
69
70 auto t4 = clock();
71
72 // reset console output
73 freopen("CON", "w", stdout);
74
75 //cout<<"res = "<<res<<"\n";
76
77 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
78 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
79 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
80
81 return 0;
82 }
83
84 bool check(const string& x)
85 {
86 if (x.length() != n)
87 {
88 return false;
89 }
90 for (int i = 0; i < n; i++)
91 {
92 if (x[i] != ’0’ && x[i] != ’1’)
93 {
94 return false;
95 }
96 }
97 return true;
98 }
99
100 void add_element(string x)
101 {
102 if (--w < 0 || compiled || !check(x))
103 {
104 printf("WA\n");
105 exit(0);
106 }
107 set_.insert(x);
108 }
109
110 bool check_element(string x)
111 {
112 if (--r < 0 || !compiled || !check(x))
113 {
114 printf("WA\n");
115 exit(0);
116 }
117 return set_.count(x);
118 }
119
120 void compile_set()
121 {
122 if (compiled)
123 {
124 printf("WA\n");
125 exit(0);
126 }
127 compiled = true;
128 set<string> compiledSet;
129 string compiledElement = string(n, ’ ’);
130 for (const string& s : set_)
131 {
CAPITOLUL 5. IOI 2016 652
284 {
285 if (!check(imp[1], imp[2], imp[3]))
286 {
287 continue;
288 }
289 found = true;
290 break;
291 }
292 } while (next_permutation(imp.begin(), imp.end()));
293
294 assert(found);
295 vector <int> ans(N, -1);
296 vector <bool> used(N, false);
297
298 for (int i = 0; i < k; i++)
299 {
300 ans[imp[i]] = i;
301 used[i] = true;
302 }
303
304 for (int i = 0; i < N; i++)
305 {
306 if (ans[i] != -1)
307 {
308 continue;
309 }
310
311 int u = 0;
312 for (int j = k - 1; j >= 0; j--)
313 {
314 int options = 0;
315 int any = -1;
316 for (int z = u; z < u + (1 << (j + 1)); z++)
317 {
318 if (!used[z])
319 {
320 options++;
321 any = z;
322 }
323 }
324
325 if (options == 1)
326 {
327 u = any;
328 break;
329 }
330 if (check(i, imp[j]))
331 {
332 u |= (1 << j);
333 }
334 }
335
336 ans[i] = u;
337 used[u] = true;
338 }
339
340 return ans;
341 }
342 /*
343 t2-t1 = 0
344 t3-t2 = 0
345 t4-t3 = 0
346
347 Process returned 0 (0x0) execution time : 0.500 s
348 Press any key to continue.
349 */
7 #include <algorithm>
8 #include <cassert>
9
10 using namespace std;
11
12 // --------------- begin grader -------------------
13
14 #include <vector>
15 #include <cstdio>
16 #include <string>
17 #include <set>
18 #include <cstdlib>
19 #include <iostream>
20
21 #include<ctime>
22
23 #include "messy.h"
24
25 using namespace std;
26
27 namespace helper
28 {
29 set<string> set_;
30 bool compiled = false;
31 int n;
32 vector<int> p;
33 int w;
34 int r;
35
36 int read_int()
37 {
38 int x;
39 cin >> x;
40 return x;
41 }
42 }
43
44 using namespace helper;
45
46 // A convenience function.
47 int get_p(int i)
48 {
49 int ret = p[i];
50 return ret;
51 }
52
53 int main()
54 {
55 auto t1 = clock();
56
57 std::freopen("../tests/subtask_4/014", "r", stdin);
58 std::freopen("4-014.out.txt", "w", stdout);
59
60 n = read_int();
61 w = read_int();
62 r = read_int();
63
64 p = vector<int>(n);
65
66 for (int i = 0; i < n; i++)
67 {
68 p[i] = read_int();
69 }
70
71 auto t2 = clock();
72
73 vector<int> answer = restore_permutation(n, w, r);
74
75 auto t3 = clock();
76
77 if (answer.size() != n)
78 {
79 printf("WA\n");
80 return 0;
81 }
82
CAPITOLUL 5. IOI 2016 656
83 printf("%d", answer[0]);
84
85 for (int i = 1; i < n; i++)
86 {
87 printf(" %d", answer[i]);
88 }
89 printf("\n");
90
91 auto t4 = clock();
92
93 // reset console output
94 freopen("CON", "w", stdout);
95
96 //cout<<"res = "<<res<<"\n";
97
98 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
99 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
100 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
101
102 return 0;
103 }
104
105 void wa()
106 {
107 printf("WA\n");
108 exit(0);
109 }
110
111 bool check(const string& x)
112 {
113 if ((int)x.length() != n)
114 {
115 return false;
116 }
117 for (int i = 0; i < n; i++)
118 {
119 if (x[i] != ’0’ && x[i] != ’1’)
120 {
121 return false;
122 }
123 }
124 return true;
125 }
126
127 void add_element(string x)
128 {
129 if (--w < 0 || compiled || !check(x))
130 {
131 wa();
132 }
133 set_.insert(x);
134 }
135
136 bool check_element(string x)
137 {
138 if (--r < 0 || !compiled || !check(x))
139 {
140 wa();
141 }
142 return set_.count(x);
143 }
144
145 void compile_set()
146 {
147 if (compiled)
148 {
149 wa();
150 }
151 compiled = true;
152 set<string> compiledSet;
153 string compiledElement = string(n, ’ ’);
154 for (set<string>::iterator it = set_.begin(); it != set_.end(); it++)
155 {
156 string s = *it;
157 for (int i = 0; i < n; i++)
158 {
CAPITOLUL 5. IOI 2016 657
67 auto t2 = clock();
68
69 vector<int> answer = restore_permutation(n, w, r);
70
71 auto t3 = clock();
72
73 if (answer.size() != n)
74 {
75 printf("WA\n");
76 return 0;
77 }
78
79 printf("%d", answer[0]);
80
81 for (int i = 1; i < n; i++)
82 {
83 printf(" %d", answer[i]);
84 }
85 printf("\n");
86
87 auto t4 = clock();
88
89 // reset console output
90 freopen("CON", "w", stdout);
91
92 //cout<<"res = "<<res<<"\n";
93
94 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
95 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
96 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
97
98 return 0;
99 }
100
101 void wa()
102 {
103 printf("WA\n");
104 exit(0);
105 }
106
107 bool check(const string& x)
108 {
109 if ((int)x.length() != n)
110 {
111 return false;
112 }
113 for (int i = 0; i < n; i++)
114 {
115 if (x[i] != ’0’ && x[i] != ’1’)
116 {
117 return false;
118 }
119 }
120 return true;
121 }
122
123 void add_element(string x)
124 {
125 if (--w < 0 || compiled || !check(x))
126 {
127 wa();
128 }
129 set_.insert(x);
130 }
131
132 bool check_element(string x)
133 {
134 if (--r < 0 || !compiled || !check(x))
135 {
136 wa();
137 }
138 return set_.count(x);
139 }
140
141 void compile_set()
142 {
CAPITOLUL 5. IOI 2016 660
143 if (compiled)
144 {
145 wa();
146 }
147 compiled = true;
148 set<string> compiledSet;
149 string compiledElement = string(n, ’ ’);
150 for (set<string>::iterator it = set_.begin(); it != set_.end(); it++)
151 {
152 string s = *it;
153 for (int i = 0; i < n; i++)
154 {
155 compiledElement[i] = s[get_p(i)];
156 }
157 compiledSet.insert(compiledElement);
158 }
159 set_ = compiledSet;
160 }
161
162 // --------------- end grader -------------------
163
164 const int N = 135;
165
166 // [l, r)
167 void go (int n, int l, int r)
168 {
169 if (l + 1 == r) return;
170 int m = l + r >> 1;
171 string s = "";
172 for (int i = 0; i < n; ++i)
173 {
174 s += ’1’;
175 }
176 for (int i = l; i < r; ++i)
177 {
178 s[i] = ’0’;
179 }
180 for (int i = l; i < m; ++i)
181 {
182 s[i] = ’1’;
183 add_element(s);
184 s[i] = ’0’;
185 }
186 go(n, l, m);
187 go(n, m, r);
188 }
189
190 vector <int> v;
191
192 // no contains positions that don’t belong to this range
193 void kill (int n, int l, int r, string no)
194 {
195 if (l + 1 == r)
196 {
197 for (int i = 0; i < n; ++i)
198 {
199 if (no[i] == ’0’)
200 {
201 v[i] = l;
202 break;
203 }
204 }
205 return;
206 }
207
208 string x = no, y = "";
209 for (int i = 0; i < n; ++i)
210 {
211 y += ’1’;
212 }
213
214 for (int i = 0; i < n; ++i)
215 {
216 if (no[i] == ’0’)
217 {
218 no[i] = ’1’;
CAPITOLUL 5. IOI 2016 661
219 if (check_element(no))
220 {
221 x[i] = ’1’;
222 y[i] = ’0’;
223 }
224 no[i] = ’0’;
225 }
226 }
227 int m = l + r >> 1;
228 kill(n, l, m, y);
229 kill(n, m, r, x);
230 }
231
232 vector <int> restore_permutation (int n, int w, int r)
233 {
234 go(n, 0, n);
235 compile_set();
236 v.resize(n);
237 string s = "";
238 for (int i = 0; i < n; ++i)
239 {
240 s += ’0’;
241 }
242 kill(n, 0, n, s);
243 return v;
244 }
245 /*
246 t2-t1 = 0
247 t3-t2 = 0.015
248 t4-t3 = 0
249
250 Process returned 0 (0x0) execution time : 0.828 s
251 Press any key to continue.
252 */
39
40 using namespace helper;
41
42 // A convenience function.
43 int get_p(int i)
44 {
45 int ret = p[i];
46 return ret;
47 }
48
49 int main()
50 {
51 auto t1 = clock();
52
53 std::freopen("../tests/subtask_4/014", "r", stdin);
54 std::freopen("4-014.out.txt", "w", stdout);
55
56 n = read_int();
57 w = read_int();
58 r = read_int();
59
60 p = vector<int>(n);
61
62 for (int i = 0; i < n; i++)
63 {
64 p[i] = read_int();
65 }
66
67 auto t2 = clock();
68
69 vector<int> answer = restore_permutation(n, w, r);
70
71 auto t3 = clock();
72
73 if (answer.size() != n)
74 {
75 printf("WA\n");
76 return 0;
77 }
78
79 printf("%d", answer[0]);
80
81 for (int i = 1; i < n; i++)
82 {
83 printf(" %d", answer[i]);
84 }
85 printf("\n");
86
87 auto t4 = clock();
88
89 // reset console output
90 freopen("CON", "w", stdout);
91
92 //cout<<"res = "<<res<<"\n";
93
94 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
95 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
96 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
97
98 return 0;
99 }
100
101 void wa()
102 {
103 printf("WA\n");
104 exit(0);
105 }
106
107 bool check(const string& x)
108 {
109 if ((int)x.length() != n)
110 {
111 return false;
112 }
113 for (int i = 0; i < n; i++)
114 {
CAPITOLUL 5. IOI 2016 663
191 {
192 if(s == e)
193 {
194 occ[c[0]] = s;
195 return;
196 }
197 int m = (s+e)/2;
198 string str;
199 for(int i=0; i<n; i++)
200 {
201 str.push_back(’0’);
202 }
203 for(auto &i : c)
204 {
205 str[i] = ’1’;
206 }
207 vector<int> l, h;
208 for(auto &j : c)
209 {
210 str[j] = ’0’;
211 if(check_element(str)) h.push_back(j);
212 else l.push_back(j);
213 str[j] = ’1’;
214 }
215 solve2(s, m, l);
216 solve2(m+1, e, h);
217 }
218
219 vector<int> restore_permutation(int _n, int w, int r)
220 {
221 n = _n;
222 solve(0, n-1);
223 compile_set();
224 vector<int> v;
225 for(int i=0; i<n; i++) v.push_back(i);
226 solve2(0, n-1, v);
227 vector<int> dap;
228 for(int i=0; i<n; i++) dap.push_back(occ[i]);
229 return dap;
230 }
231 /*
232 t2-t1 = 0
233 t3-t2 = 0
234 t4-t3 = 0
235
236 Process returned 0 (0x0) execution time : 0.984 s
237 Press any key to continue.
238 */
25 set<string> set_;
26 bool compiled = false;
27 int n;
28 vector<int> p;
29 int w;
30 int r;
31
32 int read_int()
33 {
34 int x;
35 cin >> x;
36 return x;
37 }
38 }
39
40 using namespace helper;
41
42 // A convenience function.
43 int get_p(int i)
44 {
45 int ret = p[i];
46 return ret;
47 }
48
49 int main()
50 {
51 auto t1 = clock();
52
53 std::freopen("../tests/subtask_4/014", "r", stdin);
54 std::freopen("4-014.out.txt", "w", stdout);
55
56 n = read_int();
57 w = read_int();
58 r = read_int();
59
60 p = vector<int>(n);
61
62 for (int i = 0; i < n; i++)
63 {
64 p[i] = read_int();
65 }
66
67 auto t2 = clock();
68
69 vector<int> answer = restore_permutation(n, w, r);
70
71 auto t3 = clock();
72
73 if (answer.size() != n)
74 {
75 printf("WA\n");
76 return 0;
77 }
78
79 printf("%d", answer[0]);
80
81 for (int i = 1; i < n; i++)
82 {
83 printf(" %d", answer[i]);
84 }
85 printf("\n");
86
87 auto t4 = clock();
88
89 // reset console output
90 freopen("CON", "w", stdout);
91
92 //cout<<"res = "<<res<<"\n";
93
94 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
95 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
96 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
97
98 return 0;
99 }
100
CAPITOLUL 5. IOI 2016 666
12 #include <cstdio>
13 #include <string>
14 #include <set>
15 #include <cstdlib>
16 #include <iostream>
17
18 #include<ctime>
19
20 #include "messy.h"
21
22 using namespace std;
23
24 namespace helper
25 {
26 set<string> set_;
27 bool compiled = false;
28 int n;
29 vector<int> p;
30 int w;
31 int r;
32
33 int read_int()
34 {
35 int x;
36 cin >> x;
37 return x;
38 }
39 }
40
41 using namespace helper;
42
43 // A convenience function.
44 int get_p(int i)
45 {
46 int ret = p[i];
47 return ret;
48 }
49
50 int main()
51 {
52 auto t1 = clock();
53
54 std::freopen("../tests/subtask_4/014", "r", stdin);
55 std::freopen("4-014.out.txt", "w", stdout);
56
57 n = read_int();
58 w = read_int();
59 r = read_int();
60
61 p = vector<int>(n);
62
63 for (int i = 0; i < n; i++)
64 {
65 p[i] = read_int();
66 }
67
68 auto t2 = clock();
69
70 vector<int> answer = restore_permutation(n, w, r);
71
72 auto t3 = clock();
73
74 if (answer.size() != n)
75 {
76 printf("WA\n");
77 return 0;
78 }
79
80 printf("%d", answer[0]);
81
82 for (int i = 1; i < n; i++)
83 {
84 printf(" %d", answer[i]);
85 }
86 printf("\n");
87
CAPITOLUL 5. IOI 2016 669
88 auto t4 = clock();
89
90 // reset console output
91 freopen("CON", "w", stdout);
92
93 //cout<<"res = "<<res<<"\n";
94
95 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
96 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
97 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
98
99 return 0;
100 }
101
102 void wa()
103 {
104 printf("WA\n");
105 exit(0);
106 }
107
108 bool check(const string& x)
109 {
110 if ((int)x.length() != n)
111 {
112 return false;
113 }
114 for (int i = 0; i < n; i++)
115 {
116 if (x[i] != ’0’ && x[i] != ’1’)
117 {
118 return false;
119 }
120 }
121 return true;
122 }
123
124 void add_element(string x)
125 {
126 if (--w < 0 || compiled || !check(x))
127 {
128 wa();
129 }
130 set_.insert(x);
131 }
132
133 bool check_element(string x)
134 {
135 if (--r < 0 || !compiled || !check(x))
136 {
137 wa();
138 }
139 return set_.count(x);
140 }
141
142 void compile_set()
143 {
144 if (compiled)
145 {
146 wa();
147 }
148 compiled = true;
149 set<string> compiledSet;
150 string compiledElement = string(n, ’ ’);
151 for (set<string>::iterator it = set_.begin(); it != set_.end(); it++)
152 {
153 string s = *it;
154 for (int i = 0; i < n; i++)
155 {
156 compiledElement[i] = s[get_p(i)];
157 }
158 compiledSet.insert(compiledElement);
159 }
160 set_ = compiledSet;
161 }
162
163 // --------------- end grader -------------------
CAPITOLUL 5. IOI 2016 670
164
165 // [l..r)
166 void Add(int l, int r, string base)
167 {
168 if (l + 1 == r) return;
169 int mid = (l + r) / 2;
170 for (int i = l; i < mid; ++i)
171 {
172 base[i] = ’1’;
173 add_element(base.c_str());
174 base[i] = ’0’;
175 }
176
177 // fill one side, recurse in other side
178 fill(base.begin() + l, base.begin() + mid, ’1’);
179 Add(mid, r, base);
180 fill(base.begin() + l, base.begin() + mid, ’0’);
181 fill(base.begin() + mid, base.begin() + r, ’1’);
182 Add(l, mid, base);
183 }
184
185 vector<int> ans;
186
187 void Solve(int l, int r, vector<int> miss, string base)
188 {
189 if (l + 1 == r)
190 {
191 ans[miss[0]] = l;
192 return;
193 }
194 vector<int> grL, grR;
195 for (int x: miss)
196 {
197 base[x] = ’1’;
198 if (check_element(base.c_str())) grL.push_back(x);
199 else grR.push_back(x);
200 base[x] = ’0’;
201 }
202 int mid = (l + r) / 2;
203
204 // fill one side, recurse in other side
205 for (int x: grR) base[x] = ’1’;
206 Solve(l, mid, grL, base);
207 for (int x: grR) base[x] = ’0’;
208 for (int x: grL) base[x] = ’1’;
209 Solve(mid, r, grR, base);
210 }
211
212 vector<int> restore_permutation(int n, int w, int r)
213 {
214 Add(0, n, string(n, ’0’));
215
216 compile_set();
217
218 ans.resize(n);
219 vector<int> all;
220 for (int i = 0; i < n; ++i) all.push_back(i);
221 Solve(0, n, all, string(n, ’0’));
222 return ans;
223 }
224 /*
225 t2-t1 = 0
226 t3-t2 = 0.015
227 t4-t3 = 0
228
229 Process returned 0 (0x0) execution time : 1.152 s
230 Press any key to continue.
231 */
5 #include "messy.h"
6 //#include "grader.cpp"
7
8 using namespace std;
9
10 // --------------- begin grader -------------------
11
12 #include <vector>
13 #include <cstdio>
14 #include <string>
15 #include <set>
16 #include <cstdlib>
17 #include <iostream>
18
19 #include<ctime>
20
21 #include "messy.h"
22
23 using namespace std;
24
25 namespace helper
26 {
27 set<string> set_;
28 bool compiled = false;
29 int n;
30 vector<int> p;
31 int w;
32 int r;
33
34 int read_int()
35 {
36 int x;
37 cin >> x;
38 return x;
39 }
40 }
41
42 using namespace helper;
43
44 // A convenience function.
45 int get_p(int i)
46 {
47 int ret = p[i];
48 return ret;
49 }
50
51 int main()
52 {
53 auto t1 = clock();
54
55 std::freopen("../tests/subtask_4/014", "r", stdin);
56 std::freopen("4-014.out.txt", "w", stdout);
57
58 n = read_int();
59 w = read_int();
60 r = read_int();
61
62 p = vector<int>(n);
63
64 for (int i = 0; i < n; i++)
65 {
66 p[i] = read_int();
67 }
68
69 auto t2 = clock();
70
71 vector<int> answer = restore_permutation(n, w, r);
72
73 auto t3 = clock();
74
75 if (answer.size() != n)
76 {
77 printf("WA\n");
78 return 0;
79 }
80
CAPITOLUL 5. IOI 2016 672
81 printf("%d", answer[0]);
82
83 for (int i = 1; i < n; i++)
84 {
85 printf(" %d", answer[i]);
86 }
87 printf("\n");
88
89 auto t4 = clock();
90
91 // reset console output
92 freopen("CON", "w", stdout);
93
94 //cout<<"res = "<<res<<"\n";
95
96 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
97 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
98 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
99
100 return 0;
101 }
102
103 void wa()
104 {
105 printf("WA\n");
106 exit(0);
107 }
108
109 bool check(const string& x)
110 {
111 if ((int)x.length() != n)
112 {
113 return false;
114 }
115 for (int i = 0; i < n; i++)
116 {
117 if (x[i] != ’0’ && x[i] != ’1’)
118 {
119 return false;
120 }
121 }
122 return true;
123 }
124
125 void add_element(string x)
126 {
127 if (--w < 0 || compiled || !check(x))
128 {
129 wa();
130 }
131 set_.insert(x);
132 }
133
134 bool check_element(string x)
135 {
136 if (--r < 0 || !compiled || !check(x))
137 {
138 wa();
139 }
140 return set_.count(x);
141 }
142
143 void compile_set()
144 {
145 if (compiled)
146 {
147 wa();
148 }
149 compiled = true;
150 set<string> compiledSet;
151 string compiledElement = string(n, ’ ’);
152 for (set<string>::iterator it = set_.begin(); it != set_.end(); it++)
153 {
154 string s = *it;
155 for (int i = 0; i < n; i++)
156 {
CAPITOLUL 5. IOI 2016 673
121 }
122
123 void add_element(string x)
124 {
125 if (--w < 0 || compiled || !check(x))
126 {
127 wa();
128 }
129 set_.insert(x);
130 }
131
132 bool check_element(string x)
133 {
134 if (--r < 0 || !compiled || !check(x))
135 {
136 wa();
137 }
138 return set_.count(x);
139 }
140
141 void compile_set()
142 {
143 if (compiled)
144 {
145 wa();
146 }
147 compiled = true;
148 set<string> compiledSet;
149 string compiledElement = string(n, ’ ’);
150 for (set<string>::iterator it = set_.begin(); it != set_.end(); it++)
151 {
152 string s = *it;
153 for (int i = 0; i < n; i++)
154 {
155 compiledElement[i] = s[get_p(i)];
156 }
157 compiledSet.insert(compiledElement);
158 }
159 set_ = compiledSet;
160 }
161
162 // --------------- end grader -------------------
163
164 //int n;
165 string s[1000];
166 vector<int> g;
167 void add_build(int l,int r,int v)
168 {
169 if(l==r)
170 return;
171 string t;
172 for(int i=0;i<n;i++)
173 {
174 if(i>=l && i<=r)
175 t+=’0’;
176 else
177 t+=’1’;
178 }
179 int mid=(l+r)/2;
180 for(int i=l;i<=mid;i++)
181 {
182 t[i]=’1’;
183 add_element(t);
184 t[i]=’0’;
185 }
186 add_build(l,mid,2*v);
187 add_build(mid+1,r,2*v+1);
188 }
189
190 void check_build(int l,int r,int v)
191 {
192 if(l==r)
193 {
194 for(int i=0;i<n;i++)
195 {
196 if(s[v][i]==’0’)
CAPITOLUL 5. IOI 2016 677
197 {
198 g[i]=l;
199 break;
200 }
201 }
202 return;
203 }
204
205 s[2*v]=s[v];
206 s[2*v+1]=s[v];
207 for(int i=0;i<n;i++)
208 {
209 if(s[v][i]==’1’)
210 continue;
211 s[v][i]=’1’;
212 if(check_element(s[v]))
213 s[2*v+1][i]=’1’;
214 else
215 s[2*v][i]=’1’;
216 s[v][i]=’0’;
217 }
218
219 int mid=(l+r)/2;
220 check_build(l,mid,2*v);
221 check_build(mid+1,r,2*v+1);
222 }
223
224 std::vector<int> restore_permutation(int N, int w, int r)
225 {
226 n=N;
227 for(int i=0;i<n;i++)
228 g.push_back(0);
229 add_build(0,n-1,1);
230 compile_set();
231 for(int i=0;i<n;i++)
232 s[1]+=’0’;
233 check_build(0,n-1,1);
234 return g;
235 }
236 /*
237 t2-t1 = 0
238 t3-t2 = 0
239 t4-t3 = 0
240
241 Process returned 0 (0x0) execution time : 0.125 s
242 Press any key to continue.
243 */
26 int n;
27 vector<int> p;
28 int w;
29 int r;
30
31 int read_int()
32 {
33 int x;
34 cin >> x;
35 return x;
36 }
37 }
38
39 using namespace helper;
40
41 // A convenience function.
42 int get_p(int i)
43 {
44 int ret = p[i];
45 return ret;
46 }
47
48 int main()
49 {
50 auto t1 = clock();
51
52 std::freopen("../tests/subtask_4/014", "r", stdin);
53 std::freopen("4-014.out.txt", "w", stdout);
54
55 n = read_int();
56 w = read_int();
57 r = read_int();
58
59 p = vector<int>(n);
60
61 for (int i = 0; i < n; i++)
62 {
63 p[i] = read_int();
64 }
65
66 auto t2 = clock();
67
68 vector<int> answer = restore_permutation(n, w, r);
69
70 auto t3 = clock();
71
72 if (answer.size() != n)
73 {
74 printf("WA\n");
75 return 0;
76 }
77
78 printf("%d", answer[0]);
79
80 for (int i = 1; i < n; i++)
81 {
82 printf(" %d", answer[i]);
83 }
84 printf("\n");
85
86 auto t4 = clock();
87
88 // reset console output
89 freopen("CON", "w", stdout);
90
91 //cout<<"res = "<<res<<"\n";
92
93 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
94 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
95 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
96
97 return 0;
98 }
99
100 void wa()
101 {
CAPITOLUL 5. IOI 2016 679
102 printf("WA\n");
103 exit(0);
104 }
105
106 bool check(const string& x)
107 {
108 if ((int)x.length() != n)
109 {
110 return false;
111 }
112 for (int i = 0; i < n; i++)
113 {
114 if (x[i] != ’0’ && x[i] != ’1’)
115 {
116 return false;
117 }
118 }
119 return true;
120 }
121
122 void add_element(string x)
123 {
124 if (--w < 0 || compiled || !check(x))
125 {
126 wa();
127 }
128 set_.insert(x);
129 }
130
131 bool check_element(string x)
132 {
133 if (--r < 0 || !compiled || !check(x))
134 {
135 wa();
136 }
137 return set_.count(x);
138 }
139
140 void compile_set()
141 {
142 if (compiled)
143 {
144 wa();
145 }
146 compiled = true;
147 set<string> compiledSet;
148 string compiledElement = string(n, ’ ’);
149 for (set<string>::iterator it = set_.begin(); it != set_.end(); it++)
150 {
151 string s = *it;
152 for (int i = 0; i < n; i++)
153 {
154 compiledElement[i] = s[get_p(i)];
155 }
156 compiledSet.insert(compiledElement);
157 }
158 set_ = compiledSet;
159 }
160
161 // --------------- end grader -------------------
162
163 //int n;
164 //vector<int> p;
165
166 void add(int l, int r)
167 {
168 if(l == r) return;
169 string base(n, ’1’);
170 int m = l + r >> 1;
171 for(int i = l; i <= r; i++) base[i] = ’0’;
172 for(int i = l; i <= m; i++)
173 {
174 string s = base;
175 s[i] = ’1’;
176 add_element(s);
177 }
CAPITOLUL 5. IOI 2016 680
25
26 #include<ctime>
27
28 #include "messy.h"
29
30 using namespace std;
31
32 namespace helper
33 {
34 set<string> set_;
35 bool compiled = false;
36 int n;
37 vector<int> p;
38 int w;
39 int r;
40
41 int read_int()
42 {
43 int x;
44 cin >> x;
45 return x;
46 }
47 }
48
49 using namespace helper;
50
51 // A convenience function.
52 int get_p(int i)
53 {
54 int ret = p[i];
55 return ret;
56 }
57
58 int main()
59 {
60 auto t1 = clock();
61
62 std::freopen("../tests/subtask_4/014", "r", stdin);
63 std::freopen("4-014.out.txt", "w", stdout);
64
65 n = read_int();
66 w = read_int();
67 r = read_int();
68
69 p = vector<int>(n);
70
71 for (int i = 0; i < n; i++)
72 {
73 p[i] = read_int();
74 }
75
76 auto t2 = clock();
77
78 vector<int> answer = restore_permutation(n, w, r);
79
80 auto t3 = clock();
81
82 if (answer.size() != n)
83 {
84 printf("WA\n");
85 return 0;
86 }
87
88 printf("%d", answer[0]);
89
90 for (int i = 1; i < n; i++)
91 {
92 printf(" %d", answer[i]);
93 }
94 printf("\n");
95
96 auto t4 = clock();
97
98 // reset console output
99 freopen("CON", "w", stdout);
100
CAPITOLUL 5. IOI 2016 682
5.6 Aliens
Problema 6 - Aliens 100 de puncte
Author: Chethiya Abeysinghe (Sri Lanka)
Sarcina ta este s g se³ti cel mai mic num r total posibil al celulelor fotograate.
Detalii de implementare
Trebuie s implementezi urm toarea funcµie (metod ):
Exemplul 2
Aici avem 2 puncte de interes localizate simetric în celulele (1,4) ³i (4,1). Oricare fotofrae
valid care conµine unul dintre puncte, îl va conµine ³i pe cel lalt. Prin urmare, este sucient s
e f cut o singur fotograe.
Figura care urmeaz prezint acest exemplu ³i soluµia lui optim . În aceast soluµie satelitul
capteaz o singur fotograe 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 rst 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 denition 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
solution described above. Subtask 4 allowed O n solutions. One possible solution uses the
2
Knuth's optimization.
2 2
Dene 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 .
It can be rather dicult 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 dierent 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 dierences between two
adjacent values. The following theorem states that these dierences are non-increasing. We'll call
such functions convex.
Theorem: fi,j 1 fi,j ' fi,j fi,j 1
CAPITOLUL 5. IOI 2016 688
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
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 modied to nd
the minimum number of photos required to achieve the optimum, call it p C .
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 x
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 nd such Copt that p1 p Copt ' k
and p2 p Copt 1 & k .
This means that all dierences 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 nd Copt , each iteration running in linear time.
Total running time: O n log n n log m.
33 for(int kk=0;kk<argc;kk++)
34 cout<<argv[kk]<<"\n";
35 cout<<"----------------------\n";
36
37 registerTestlibCmd(argc, argv);
38
39 long long pans = readLong(ouf);
40 long long jans = readLong(ans);
41
42 if (pans != jans)
43 {
44 quitf(_wa, "Wrong answer: output = %lld, expected = %lld", pans, jans);
45 }
46 else
47 {
48 quitf(_ok, "Correct answer: answer = %lld", pans);
49 }
50 }
55 void resetline();
56 Hull();
57 ~Hull();
58 };
59
60 Hull::Hull()
61 {
62 L = (hull_line*)malloc(MAXN * sizeof(hull_line));
63 }
64
65 Hull::~Hull()
66 {
67 free(L);
68 }
69
70 double Hull::getx(ll m1, ll c1, ll m2, ll c2)
71 {
72 return (c2-c1) / (double)(m1-m2);
73 }
74
75 void Hull::addline(ll m, ll c, ll k)
76 {
77 while (len >= 2)
78 {
79 double a = getx(m, c, L[len-1].m, L[len-1].c);
80 double b = getx(m, c, L[len-2].m, L[len-2].c);
81 if (a > b) break;
82 len--;
83 }
84 L[len].m = m;
85 L[len].c = c;
86 L[len].k = k;
87 len++;
88 }
89
90 pair<ll,ll> Hull::getmin(ll x)
91 {
92 if (cur >= len) cur = len-1;
93 while (cur < len-1)
94 {
95 double a = getx(L[cur].m, L[cur].c, L[cur+1].m, L[cur+1].c);
96 if (x > a)
97 cur++;
98 else
99 break;
100 // in case x==a first such line is considered
101 // It can be proven using convex property
102 // that k increase as cur increases
103 }
104 return make_pair(L[cur].m * x + L[cur].c, L[cur].k);
105 }
106
107 void Hull::resetline()
108 {
109 len = 0;
110 cur = 0;
111 }
112
113 pair<ll,ll> hull(vector<range> &r, ll C, Hull &h)
114 {
115 int n = r.size();
116 ll m, c;
117 ll t, lastRes = 0LL, lastK = 0LL;
118 h.resetline();
119 pair<ll,ll> res;
120 for (int i=0; i<n; ++i)
121 {
122 m = -2LL * (r[i].s - 1LL);
123 c = lastRes + sq(r[i].s - 1LL);
124 if (i > 0)
125 {
126 t = max(0LL, r[i-1].e - r[i].s + 1LL);
127 c -= sq(t);
128 }
129 h.addline(m, c, lastK);
130 res = h.getmin(r[i].e);
CAPITOLUL 5. IOI 2016 691
71 assert(is_sorted(L.begin(), L.end()));
72
73 llong ans = linf;
74 llong a = -1, b = (llong)m * m + 1;
75 while (b - a > 1)
76 {
77 llong x = (a + b) / 2;
78 vector<vt> st;
79 int pt = 0;
80 llong val = 0;
81 for (int i = 0; i <= (int)L.size(); i++)
82 {
83 val = 0;
84 if (i)
85 {
86 int r2 = R[i - 1];
87 vt dir(1, r2);
88 while (pt + 1 < (int)st.size())
89 {
90 llong scal1 = st[pt] * dir;
91 llong scal2 = st[pt + 1] * dir;
92 if (scal2 < scal1)
93 pt++;
94 else
95 break;
96 }
97 val = st[pt] * dir + x + (llong)r2 * r2;
98 }
99
100 int r1 = i ? R[i - 1] : -1;
101 int l = L[i] - 1;
102 vt cur(val + (llong)l * l - sqr(max(0, r1 - l)), -2 * l);
103 cur.num = (i == 0) ? 0 : st[pt].num + 1;
104 while (st.size() >= 2 &&
105 ((st[(int)st.size() - 1] -
106 st[(int)st.size() - 2]) ^
107 (cur - st[(int)st.size() - 1])) < 0)
108 st.pop_back();
109
110 st.push_back(cur);
111 pt = min(pt, (int)st.size() - 1);
112 }
113
114 int cnt = st.back().num;
115 if (cnt > k)
116 a = x;
117 else {
118 ans = val;
119 b = x;
120 }
121 }
122 ans -= b * k;
123
124 return ans;
125 }
126
127 // BEGIN CUT
128
129 int main()
130 {
131 auto t1 = clock();
132
133 std::freopen("../tests/subtask_6/175", "r", stdin);
134 std::freopen("6-175.out.txt", "w", stdout);
135
136 int n, m, k;
137 scanf("%d %d %d", &n, &m, &k);
138 std::vector<int> r(n), c(n);
139 for (int i = 0; i < n; i++)
140 {
141 scanf("%d %d", &r[i], &c[i]);
142 }
143
144 auto t2 = clock();
145
146 long long ans = take_photos(n, m, k, r, c);
CAPITOLUL 5. IOI 2016 695
147
148 auto t3 = clock();
149
150 // BEGIN SECRET
151 //puts("098d134608c94f7413faac591054ee35");
152 // END SECRET
153
154 printf("%lld\n", ans);
155
156 auto t4 = clock();
157
158 // reset console output
159 freopen("CON", "w", stdout);
160
161 //cout<<"ans = "<<ans<<"\n";
162
163 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
164 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
165 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
166
167 return 0;
168 }
169
170 // END CUT
171 /*
172 t2-t1 = 0.312
173 t3-t2 = 1.609
174 t4-t3 = 0
175
176 Process returned 0 (0x0) execution time : 1.953 s
177 Press any key to continue.
178 */
41 }
42 double slope()
43 {
44 return y / x;
45 }
46 };
47
48 long long take_photos(int n, int m, int k, vector<int> row, vector<int> column)
49 {
50 map<int, int> M;
51 for (int i = 0; i < n; i++)
52 {
53 int x, y;
54 x = row[i];
55 y = column[i];
56 if (x < y)
57 swap(x, y);
58 if (!M.count(x))
59 M[x] = x;
60 M[x] = min(M[x], y);
61 }
62
63 vector<int> L, R;
64 for (auto pr : M)
65 {
66 while (!L.empty() && L.back() >= pr.second)
67 L.pop_back(), R.pop_back();
68 R.push_back(pr.first);
69 L.push_back(pr.second);
70 }
71
72 n = L.size();
73 assert(is_sorted(R.begin(), R.end()));
74 assert(is_sorted(L.begin(), L.end()));
75
76 llong ans = linf;
77 llong a = -1, b = (llong)m * m + 1;
78 while (b - a > 1)
79 {
80 llong x = (a + b) / 2;
81 vector<vt> st;
82 int pt = 0;
83 llong val = 0;
84 for (int i = 0; i <= (int)L.size(); i++)
85 {
86 val = 0;
87 if (i)
88 {
89 int r2 = R[i - 1];
90 vt dir(1, r2);
91 while (pt + 1 < (int)st.size())
92 {
93 llong scal1 = st[pt] * dir;
94 llong scal2 = st[pt + 1] * dir;
95 if (scal2 < scal1)
96 pt++;
97 else
98 break;
99 }
100 val = st[pt] * dir + x + (llong)r2 * r2;
101 }
102
103 int r1 = i ? R[i - 1] : -1;
104 int l = L[i] - 1;
105 vt cur(val + (llong)l * l - sqr(max(0, r1 - l)), -2 * l);
106 cur.num = (i == 0) ? 0 : st[pt].num + 1;
107 while (st.size() >= 2 &&
108 (st[(int)st.size() - 1] -
109 st[(int)st.size() - 2]).slope() >
110 (cur - st[(int)st.size() - 1]).slope())
111 st.pop_back();
112
113 st.push_back(cur);
114 pt = min(pt, (int)st.size() - 1);
115 }
116
CAPITOLUL 5. IOI 2016 697
9
10 #include<ctime>
11
12 using namespace std;
13
14 typedef long long llong;
15 typedef long double ld;
16
17 struct point
18 {
19 int x, y;
20 bool operator<(const point &p) const
21 {
22 return x < p.x || (x == p.x && y > p.y);
23 }
24 };
25
26 int n, m, k;
27 vector<point> _ps;
28 vector<point> ps;
29
30 llong sqr(int x)
31 {
32 return (llong)x * x;
33 }
34
35 struct line
36 {
37 int cnt;
38 llong m, b;
39 } st[100000];
40
41 int top, bot;
42
43 void push(line x)
44 {
45 while (top > bot && (ld)(x.b - st[top].b) / (st[top].m - x.m)
46 <= (ld)(st[top - 1].b - st[top].b) / (st[top].m - st[top - 1].m))
47 --top;
48 st[++top] = x;
49 }
50
51 llong func(line l, int x)
52 {
53 return l.m * x + l.b;
54 }
55
56 pair<int, llong> query(int x)
57 {
58 while (top > bot && func(st[bot + 1], x) <= func(st[bot], x)) ++bot;
59 return { st[bot].cnt, func(st[bot], x) };
60 }
61
62 llong dp[100000];
63 int cnt[100000];
64
65 //dp[i] = min(dp[j] + x[j + 1] ^ 2 - 2 * x[j + 1] * y[i] + y[i] ^ 2 + cost);
66
67 int getPhoto(llong c)
68 {
69 top = -1; bot = 0;
70 push({ 0, -2ll * ps[0].x, sqr(ps[0].x) });
71 for (int i = 0; i < n; ++i)
72 {
73 auto ret = query(ps[i].y + 1);
74 dp[i] = ret.second + sqr(ps[i].y + 1) + c;
75 cnt[i] = ret.first + 1;
76 if (i < n - 1)
77 push({ cnt[i],
78 -2ll * ps[i + 1].x,
79 dp[i] + sqr(ps[i + 1].x) -
80 sqr(max(0, ps[i].y - ps[i + 1].x + 1)) });
81 }
82 return cnt[n - 1];
83 }
84
CAPITOLUL 5. IOI 2016 699
161
162 // BEGIN SECRET
163 //puts("098d134608c94f7413faac591054ee35");
164 // END SECRET
165
166 printf("%lld\n", ans);
167
168 auto t4 = clock();
169
170 // reset console output
171 freopen("CON", "w", stdout);
172
173 //cout<<"ans = "<<ans<<"\n";
174
175 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
176 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
177 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
178
179 return 0;
180 }
181
182 // END CUT
183 /*
184 t2-t1 = 0.328
185 t3-t2 = 0.609
186 t4-t3 = 0
187
188 Process returned 0 (0x0) execution time : 1.219 s
189 Press any key to continue.
190 */
43 top = 0; bx = 0;
44 add_line(-2*x[0], sqr(x[0]), -1);
45 for(int i=0; i<pn; ++i)
46 {
47 while(bx+1 < top && f(bx, y[i]+1) > f(bx+1, y[i]+1)) ++bx;
48 dp[i]=f(bx, y[i]+1)+sqr(y[i]+1)+cost;
49 lst[i]=lid[bx];
50 if(i+1 < pn)
51 {
52 add_line(-2*x[i+1],
53 dp[i]+sqr(x[i+1])-sqr(max(0ll, y[i]-x[i+1]+1)),
54 i);
55 bx = min(bx, top-1);
56 }
57 }
58 int cnt = 0;
59 for(int i=pn-1; i!=-1; i=lst[i]) ++cnt;
60 return cnt;
61 }
62
63 long long take_photos(int n, int m, int k,
64 std::vector<int> r, std::vector<int> c)
65 {
66 for(int i=0; i<n; ++i)
67 {
68 int x=r[i], y=c[i];
69 if(x>y) swap(x, y);
70 po[i]={x, y};
71 }
72
73 sort(po, po+n);
74
75 for(int i=0; i<n; ++i)
76 {
77 int cx=po[i].first, cy=po[i].second;
78 if(!pn)
79 {
80 x[pn]=cx; y[pn]=cy; ++pn;
81 continue;
82 }
83 if(x[pn-1] == cx) y[pn-1] = cy;
84 else if(y[pn-1] < cy) x[pn]=cx, y[pn]=cy, ++pn;
85 }
86
87 ll cl = -1, cr = m*1LL*m;
88 while(cl+1 < cr)
89 {
90 ll mid = (cl+cr)/2;
91 (F(mid) <= k ? cr : cl) = mid;
92 }
93
94 F(cr);
95 return dp[pn-1]-cr*k;
96 }
97
98 // BEGIN CUT
99
100 int main()
101 {
102 auto t1 = clock();
103
104 std::freopen("../tests/subtask_6/175", "r", stdin);
105 std::freopen("6-175.out.txt", "w", stdout);
106
107 int n, m, k;
108 scanf("%d %d %d", &n, &m, &k);
109 std::vector<int> r(n), c(n);
110 for (int i = 0; i < n; i++)
111 {
112 scanf("%d %d", &r[i], &c[i]);
113 }
114
115 auto t2 = clock();
116
117 long long ans = take_photos(n, m, k, r, c);
118
CAPITOLUL 5. IOI 2016 702
118 }
119
120 auto t2 = clock();
121
122 long long ans = take_photos(n, m, k, r, c);
123
124 auto t3 = clock();
125
126 // BEGIN SECRET
127 //puts("098d134608c94f7413faac591054ee35");
128 // END SECRET
129
130 printf("%lld\n", ans);
131
132 auto t4 = clock();
133
134 // reset console output
135 freopen("CON", "w", stdout);
136
137 //cout<<"ans = "<<ans<<"\n";
138
139 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
140 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
141 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
142
143 return 0;
144 }
145
146 // END CUT
147 /*
148 t2-t1 = 0.296
149 t3-t2 = 4.025
150 t4-t3 = 0
151
152 Process returned 0 (0x0) execution time : 4.602 s
153 Press any key to continue.
154 */
36
37 vector<line> f;
38 bool bad(line l1, line l2, line l3)
39 {
40 return (l1.c - l3.c) * (l2.m - l1.m) <=
41 (l3.m - l1.m) * (l1.c - l2.c);
42 }
43
44 void update(long long m, long long c, int cnt)
45 {
46 line l(m, c, cnt);
47 while(f.size() >= 2 and bad(f[f.size()-2], f[f.size()-1], l))
48 f.pop_back();
49 f.emplace_back(l);
50 }
51
52 int idx;
53 pair<long long, int> query(long long x)
54 {
55 while(idx + 1 < f.size() and f[idx+1].get(x) < f[idx].get(x))
56 ++idx;
57 return make_pair(f[idx].get(x), f[idx].cnt);
58 }
59
60 void clear()
61 {
62 f.clear(), idx = 0;
63 }
64 } hull;
65
66 long long sq(long long x) { return x * x; }
67
68 pair<long long, int> f(long long C)
69 {
70 vector<pair<long long, int> > dp(V.size()+1);
71 hull.clear();
72 hull.update(-2*(V[0].x-1), sq(V[0].x-1), 0);
73 for(int i = 1; i <= V.size(); ++i)
74 {
75 auto ret = hull.query(V[i-1].y);
76 dp[i] = make_pair(ret.x + sq(V[i-1].y) + C, ret.y + 1);
77 if(i != V.size())
78 hull.update(-2*(V[i].x-1),
79 sq(V[i].x-1) +
80 dp[i].x -
81 sq(max(0, V[i-1].y - V[i].x + 1)),
82 dp[i].y);
83 }
84 return dp.back();
85 }
86
87 long long take_photos(int n, int m, int k,
88 vector<int> _r, vector<int> c)
89 {
90 for(int i = 0; i < n; ++i)
91 V.emplace_back(min(_r[i], c[i]), max(_r[i], c[i]));
92 compress();
93 long long l = 0, r = 1e12;
94 while(l < r)
95 {
96 long long m = l + r >> 1;
97 if(f(m).y <= k) r = m;
98 else l = m+1;
99 }
100 return f(r).x - r*k;
101 }
102
103 // BEGIN CUT
104
105 int main()
106 {
107 auto t1 = clock();
108
109 std::freopen("../tests/subtask_6/175", "r", stdin);
110 std::freopen("6-175.out.txt", "w", stdout);
111
CAPITOLUL 5. IOI 2016 706
112 int n, m, k;
113 scanf("%d %d %d", &n, &m, &k);
114 std::vector<int> r(n), c(n);
115 for (int i = 0; i < n; i++)
116 {
117 scanf("%d %d", &r[i], &c[i]);
118 }
119
120 auto t2 = clock();
121
122 long long ans = take_photos(n, m, k, r, c);
123
124 auto t3 = clock();
125
126 // BEGIN SECRET
127 //puts("098d134608c94f7413faac591054ee35");
128 // END SECRET
129
130 printf("%lld\n", ans);
131
132 auto t4 = clock();
133
134 // reset console output
135 freopen("CON", "w", stdout);
136
137 //cout<<"ans = "<<ans<<"\n";
138
139 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
140 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
141 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
142
143 return 0;
144 }
145
146 // END CUT
147 /*
148 t2-t1 = 0.296
149 t3-t2 = 1.313
150 t4-t3 = 0
151
152 Process returned 0 (0x0) execution time : 1.875 s
153 Press any key to continue.
154 */
30 }
31 }
32 swap(p, new_p);
33 n = p.size();
34 }
35
36 k = min(k, n);
37 vector<int> x(n), y(n);
38
39 for (int i = 0; i < n; ++i)
40 {
41 x[i] = p[i].first;
42 y[i] = p[i].second;
43 }
44
45 vector<long long> f(n + 1);
46 vector<int> g(n + 1);
47 auto sqr = [&](int x)
48 {
49 return (long long) x * x;
50 };
51
52 auto solve = [&](long long c)
53 {
54 vector<int> q(n + 1);
55 int l = 0, r = 0;
56 auto check = [&](int a, int b, int c)
57 {
58 return (f[a] + sqr(x[a]) - f[c] - sqr(x[c])) * (x[b] - x[c]) <
59 (f[b] + sqr(x[b]) - f[c] - sqr(x[c])) * (x[a] - x[c]);
60 };
61
62 for (int i = 0; i < n; ++i)
63 {
64 while (r - l > 1 && check(i, q[r - 1], q[r - 2]))
65 {
66 --r;
67 }
68
69 q[r++] = i;
70 while (r - l > 1 && f[q[l]] + sqr(y[i] - x[q[l]] + 1) >
71 f[q[l + 1]] + sqr(y[i] - x[q[l + 1]] + 1))
72 {
73 ++l;
74 }
75
76 f[i + 1] = f[q[l]] + sqr(y[i] - x[q[l]] + 1) + c;
77 if (i + 1 < n && y[i] >= x[i + 1])
78 {
79 f[i + 1] -= sqr(y[i] - x[i + 1] + 1);
80 }
81 g[i + 1] = g[q[l]] + 1;
82 }
83 };
84
85 long long low = 0, high = 1ll << 40;
86
87 while (low < high)
88 {
89 long long mid = low + high >> 1;
90 solve(mid);
91 if (g[n] <= k)
92 {
93 high = mid;
94 }
95 else
96 {
97 low = mid + 1;
98 }
99 }
100
101 solve(high);
102 return f[n] - k * high;
103 }
104
105 // BEGIN CUT
CAPITOLUL 5. IOI 2016 708
106
107 int main()
108 {
109 auto t1 = clock();
110
111 std::freopen("../tests/subtask_6/175", "r", stdin);
112 std::freopen("6-175.out.txt", "w", stdout);
113
114 int n, m, k;
115 scanf("%d %d %d", &n, &m, &k);
116 std::vector<int> r(n), c(n);
117 for (int i = 0; i < n; i++)
118 {
119 scanf("%d %d", &r[i], &c[i]);
120 }
121
122 auto t2 = clock();
123
124 long long ans = take_photos(n, m, k, r, c);
125
126 auto t3 = clock();
127
128 // BEGIN SECRET
129 //puts("098d134608c94f7413faac591054ee35");
130 // END SECRET
131
132 printf("%lld\n", ans);
133
134 auto t4 = clock();
135
136 // reset console output
137 freopen("CON", "w", stdout);
138
139 //cout<<"ans = "<<ans<<"\n";
140
141 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
142 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
143 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
144
145 return 0;
146 }
147
148 // END CUT
149 /*
150 t2-t1 = 0.296
151 t3-t2 = 1.282
152 t4-t3 = 0
153
154 Process returned 0 (0x0) execution time : 1.844 s
155 Press any key to continue.
156 */
22
23 bool is_delect(node x,node y,node z)
24 {
25 return (x.x-z.x)*(y.y-x.y)>=(x.x-y.x)*(z.y-x.y)?true:false;
26 }
27
28 void add(LL x,LL y,LL i)
29 {
30 while(e-s>1 && is_delect(line[e-2],line[e-1],{x,y})) e--;
31 line[e++]={x,y,i};
32 }
33
34 LL get_val(LL i,LL x){return line[i].x*x+line[i].y;}
35
36 LL is_ok(LL x)
37 {
38 LL i;
39 s=e=0;
40 add(-2*V[1].x,sq(V[1].x)-2*V[1].x,0);
41 for(i=1;i<=n;i++)
42 {
43 while(e-s>1 && get_val(s,V[i].y)>=get_val(s+1,V[i].y)) s++;
44 dp[i]=get_val(s,V[i].y)+sq(V[i].y+1)+x;
45 from[i]=line[s].i;
46 add(-2*V[i+1].x,
47 sq(V[i+1].x)+
48 dp[i]-2*V[i+1].x-
49 sq(max(0LL,V[i].y-V[i+1].x+1)),
50 i);
51 }
52 i=n;
53 LL c;
54 for(c=0;i;i=from[i],c++);
55
56 return c;
57 }
58
59 long long take_photos(int N, int M, int K,
60 std::vector<int> r, std::vector<int> c)
61 {
62 LL i,x,y;
63 n=N;
64 m=M;
65 k=K;
66 for(i=1;i<=n;i++)
67 V[i]={min(r[i-1],c[i-1]),max(r[i-1],c[i-1])};
68
69 sort(V+1,
70 V+n+1,
71 [&](const node x,const node y)
72 {
73 return (x.x==y.x)?x.y>y.y:x.x<y.x;
74 });
75 m=n;
76 n=0;
77 x=-inf;
78 for(i=1;i<=m;i++)
79 {
80 if(x>=V[i].y) continue;
81 V[++n]=V[i];
82 x=V[i].y;
83 }
84
85 LL l,rr;
86 l=0;
87 rr=sq((LL)M);
88 k=min(k,n);
89 LL mid,ans=0;
90 while(l<=rr)
91 {
92 mid=(l+rr)>>1;
93 x=is_ok(mid);
94 if(x==k) return dp[n]-k*mid;
95 if(x<k) rr=mid-1;
96 else
97 {
CAPITOLUL 5. IOI 2016 710
98 l=mid+1;
99 ans=max(ans,dp[n]-k*mid);
100 }
101 }
102 return ans;
103 }
104
105 // BEGIN CUT
106
107 int main()
108 {
109 auto t1 = clock();
110
111 std::freopen("../tests/subtask_6/175", "r", stdin);
112 std::freopen("6-175.out.txt", "w", stdout);
113
114 int n, m, k;
115 scanf("%d %d %d", &n, &m, &k);
116 std::vector<int> r(n), c(n);
117 for (int i = 0; i < n; i++)
118 {
119 scanf("%d %d", &r[i], &c[i]);
120 }
121
122 auto t2 = clock();
123
124 long long ans = take_photos(n, m, k, r, c);
125
126 auto t3 = clock();
127
128 // BEGIN SECRET
129 //puts("098d134608c94f7413faac591054ee35");
130 // END SECRET
131
132 printf("%lld\n", ans);
133
134 auto t4 = clock();
135
136 // reset console output
137 freopen("CON", "w", stdout);
138
139 //cout<<"ans = "<<ans<<"\n";
140
141 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
142 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
143 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
144
145 return 0;
146 }
147
148 // END CUT
149 /*
150 t2-t1 = 0.312
151 t3-t2 = 0.438
152 t4-t3 = 0
153
154 Process returned 0 (0x0) execution time : 1.016 s
155 Press any key to continue.
156 */
14
15 int c[100009];
16 ll D[100009];
17
18 inline ll p(ll x) { return x*x; }
19
20 struct line
21 {
22 ll a, b;
23 int idx;
24 };
25
26 line stk[100009]; int t, j;
27
28 inline bool del(line P, line Q, line R)
29 {
30 return (R.a - P.a) * (Q.b - R.b) < (R.a - Q.a) * (P.b - R.b);
31 }
32
33 void add(line P)
34 {
35 while(1<=t && del(stk[t-1], stk[t], P)) --t, j = min(j, t);
36 stk[++t] = P;
37 }
38
39 pli DP(vector<pll>& A, ll lambda)
40 {
41 int N = (int)A.size() - 1;
42 for(int i=1; i<N; i++)
43 D[i] = 1LL * 1e18, c[i] = 0;
44 t = -1;
45 add((line){-2LL * A[1].fi, p(A[1].fi) - 2*A[1].fi, 0});
46 j = 0;
47 for(int i=1; i<N; i++)
48 {
49 while(j<t &&
50 A[i].se * stk[j].a + stk[j].b >
51 A[i].se * stk[j+1].a + stk[j+1].b)
52 ++j;
53
54 ll nw = A[i].se * stk[j].a +
55 stk[j].b + p(A[i].se) +
56 2*A[i].se + 1 +
57 lambda;
58
59 if(D[i] > nw)
60 D[i] = nw, c[i] = c[stk[j].idx] + 1;
61
62 add({-2LL * A[i+1].fi,
63 D[i] +
64 p(A[i+1].fi) -
65 2*A[i+1].fi -
66 p(max(0LL, A[i].se - A[i+1].fi + 1)),
67 i});
68 }
69
70 return {D[N-1], c[N-1]};
71 }
72
73 long long take_photos(int n, int m, int k, vector<int> r, vector<int> c)
74 {
75 vector<pll> A, B;
76 for(int i=0; i<n; i++)
77 {
78 if(r[i] > c[i]) swap(r[i], c[i]);
79 A.push_back({r[i], c[i]});
80 }
81
82 sort(A.begin(), A.end(), [&](pll P, pll Q)
83 {
84 if(P.se == Q.se) return P.fi > Q.fi;
85 return P.se < Q.se;
86 });
87 B.push_back({-1, -1});
88 for(int i=0; i<n; i++)
89 {
CAPITOLUL 5. IOI 2016 712
4 #include <bits/stdc++.h>
5
6 #define eb emplace_back
7 #define sz(V) ((int)(V).size())
8 #define allv(V) ((V).begin()),((V).end())
9 #define sorv(V) sort(allv(V))
10 #define univ(V) (V).erase(unique(allv(V)),(V).end())
11 #define befv(V) ((V)[sz(V)-2])
12 #define upmin(a,b) (a)=min((a),(b))
13 #define INFLL (0x3f3f3f3f3f3f3f3fll)
14
15 using namespace std;
16
17 typedef long long ll;
18 typedef pair<int, int> pii;
19 typedef pair<int, ll> pil;
20 typedef pair<ll, ll> pll;
21
22 ll pw(ll n) { return n*n; }
23
24 ll operator * (const pll &a, const pll &b)
25 {
26 return a.first*b.second - b.first*a.second;
27 }
28
29 ll ccw(const pll &a, const pll &b, const pll &c)
30 {
31 return a*b + b*c + c*a;
32 }
33
34 const int MAXN = 100055;
35
36 struct CHT
37 {
38 pll P[MAXN];
39 int I[MAXN], n, pv;
40
41 void init() { n = pv = 0; }
42 void push(ll a, ll b, int c)
43 {
44 pll p(a, b);
45 for(; 1 < n && 0 <= ccw(P[n-2], P[n-1], p); n--);
46 P[n] = p;
47 I[n] = c;
48 n++;
49 }
50
51 ll f(int i, ll X) { return P[i].first * X + P[i].second; }
52
53 pil get(ll X)
54 {
55 if(n <= pv) pv = n-1;
56 for(ll nw, nxt; pv+1 < n; pv++)
57 {
58 nw = f(pv, X); nxt = f(pv+1, X);
59 if(nw <= nxt) break;
60 }
61 return pil(I[pv], f(pv, X));
62 }
63 } cht;
64
65 ll C[MAXN], D[MAXN];
66 int E[MAXN];
67
68 int X[MAXN], Y[MAXN];
69
70 int N, M, K;
71
72 void push(int i)
73 {
74 cht.push(-2ll*X[i], D[i-1] + pw(X[i]) - C[i] - 2ll*X[i], i);
75 }
76
77 int f(ll L)
78 {
79 cht.init();
CAPITOLUL 5. IOI 2016 714
156
157 // BEGIN CUT
158
159 int main()
160 {
161 auto t1 = clock();
162
163 std::freopen("../tests/subtask_6/175", "r", stdin);
164 std::freopen("6-175.out.txt", "w", stdout);
165
166 int n, m, k;
167 scanf("%d %d %d", &n, &m, &k);
168 std::vector<int> r(n), c(n);
169 for (int i = 0; i < n; i++)
170 {
171 scanf("%d %d", &r[i], &c[i]);
172 }
173
174 auto t2 = clock();
175
176 long long ans = take_photos(n, m, k, r, c);
177
178 auto t3 = clock();
179
180 // BEGIN SECRET
181 //puts("098d134608c94f7413faac591054ee35");
182 // END SECRET
183
184 printf("%lld\n", ans);
185
186 auto t4 = clock();
187
188 // reset console output
189 freopen("CON", "w", stdout);
190
191 //cout<<"ans = "<<ans<<"\n";
192
193 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
194 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
195 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
196
197 return 0;
198 }
199
200 // END CUT
201 /*
202 t2-t1 = 0.3
203 t3-t2 = 0.781
204 t4-t3 = 0
205
206 Process returned 0 (0x0) execution time : 1.441 s
207 Press any key to continue.
208 */
96 return ans;
97 }
98
99 // BEGIN CUT
100
101 int main()
102 {
103 auto t1 = clock();
104
105 std::freopen("../tests/subtask_6/175", "r", stdin);
106 std::freopen("6-175.out.txt", "w", stdout);
107
108 int n, m, k;
109 scanf("%d %d %d", &n, &m, &k);
110 std::vector<int> r(n), c(n);
111 for (int i = 0; i < n; i++)
112 {
113 scanf("%d %d", &r[i], &c[i]);
114 }
115
116 auto t2 = clock();
117
118 long long ans = take_photos(n, m, k, r, c);
119
120 auto t3 = clock();
121
122 // BEGIN SECRET
123 //puts("098d134608c94f7413faac591054ee35");
124 // END SECRET
125
126 printf("%lld\n", ans);
127
128 auto t4 = clock();
129
130 // reset console output
131 freopen("CON", "w", stdout);
132
133 //cout<<"ans = "<<ans<<"\n";
134
135 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
136 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
137 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
138
139 return 0;
140 }
141
142 // END CUT
143 /*
144 t2-t1 = 0.359
145 t3-t2 = 0.812
146 t4-t3 = 0
147
148 Process returned 0 (0x0) execution time : 1.469 s
149 Press any key to continue.
150 */
18 struct Line { ll a, b, k; };
19
20 double cross(const Line &p, const Line &q)
21 {
22 return (double)(q.b-p.b)/(p.a-q.a);
23 }
24
25 vector<Line> S;
26
27 void update(Line p)
28 {
29 while(S.size()>1 &&
30 cross(S[S.size()-1], p) <=
31 cross(S[S.size()-1], S[S.size()-2]))
32 S.pop_back();
33
34 S.push_back(p);
35 }
36
37 int pos=0;
38 pll query(ll x)
39 {
40 if(S.size()<=pos)
41 pos=S.size()-1;
42 else
43 while(pos+1<S.size() && cross(S[pos], S[pos+1])<=x)
44 pos++;
45
46 return {S[pos].a*x+S[pos].b, S[pos].k};
47 }
48
49 void init()
50 {
51 S.clear();
52 pos=0;
53 }
54 } cht;
55
56 int N, M, K;
57 Point B[MAXN+10], A[MAXN+10];
58 pll dp[MAXN+10];
59
60 ll solve(ll lambda)
61 {
62 int i, j;
63 cht.init();
64 for(i=1; i<=N; i++)
65 {
66 dp[i]={2*(A[i].y-A[1].x+1)*(A[i].y-A[1].x+1)+lambda, 1};
67 if(i!=1)
68 {
69 pll val=cht.query(A[i].y);
70 dp[i]=min(dp[i],
71 {val.first+2*A[i].y*A[i].y+lambda, val.second+1});
72 }
73
74 cht.update({-2*2*(A[i+1].x-1),
75 2*(A[i+1].x-1)*(A[i+1].x-1)-
76 2*max(0ll, A[i].y-A[i+1].x+1)*
77 max(0ll, A[i].y-A[i+1].x+1)+
78 dp[i].first,
79 dp[i].second});
80 }
81
82 return dp[N].second;
83 }
84
85 ll take_photos(int _N, int _M, int _K, vector<int> R, vector<int> C)
86 {
87 int i, j, k;
88 N=_N; M=_M; K=_K;
89
90 for(i=1; i<=N; i++)
91 B[i]={min(R[i-1], C[i-1]), max(R[i-1], C[i-1])};
92 sort(B+1, B+N+1, [&](const Point &p, const Point &q)
93 {
CAPITOLUL 5. IOI 2016 719
170 t4-t3 = 0
171
172 Process returned 0 (0x0) execution time : 2.063 s
173 Press any key to continue.
174 */
68 line.push_back(nl);
69 }
70
71 int get_take(ll c)
72 {
73 cur=0;
74 line.clear();
75 add(Line(-2*(p[1].fi-1),c+(p[1].fi-1)*(p[1].fi-1),1));
76
77 pll t;
78 for(int i=1;i<(int)p.size();i++)
79 {
80 if(i>1)
81 {
82 if(p[i].fi<=p[i-1].se)
83 add(Line(-2*(p[i].fi-1),
84 c+t.fi+
85 (p[i].fi-1)*(p[i].fi-1) -
86 (p[i-1].se-p[i].fi+1)*(p[i-1].se-p[i].fi+1),
87 t.se+1));
88 else
89 add(Line(-2*(p[i].fi-1),
90 c+t.fi+(p[i].fi-1)*(p[i].fi-1),
91 t.se+1));
92 }
93
94 t = get(p[i].se);
95 t.fi+=p[i].se*p[i].se;
96 dp[i]=t.fi;
97 }
98
99 return (int)t.se;
100 }
101
102 ll take_photos(int n, int m, int k, vector<int>x, vector<int>y)
103 {
104 k=min(n,k);
105 for(int i=0;i<n;i++)
106 {
107 if(x[i]>y[i]) swap(x[i], y[i]);
108 tmp.pb({x[i],y[i]});
109 }
110
111 sort(tmp.begin(), tmp.end(), [](pii a, pii b)
112 {
113 if(a.se==b.se)
114 return a.fi>b.fi;
115 return a.se<b.se;
116 });
117 p.pb({-1,-1});
118 for(auto i:tmp)
119 {
120 while(!p.empty()&&p[p.size()-1].fi>=i.fi)
121 p.pop_back();
122 p.pb(i);
123 }
124
125 k=min(k,(int)p.size()-1);
126 ll s = 0,e=(ll)m*m;
127 ll l=-1,r=e+1,ly,ry;
128
129 while(s<=e)
130 {
131 ll mid = (s+e)/2;
132 int num = get_take(mid);
133 if(num==k) return dp[p.size()-1]-mid*k;
134 if(num>k)
135 {
136 s = mid+1;
137 if(r>num) r=num,ry=dp[p.size()-1]-mid*num;
138 }
139
140 if(num<k)
141 {
142 e = mid-1;
143 if(l<num) l=num,ly=dp[p.size()-1]-mid*num;
CAPITOLUL 5. IOI 2016 722
144 }
145 }
146
147 if(r==(ll)m*m+1) return ly;
148 if(l==-1) return ry;
149 return ry+(ly-ry)/(r-l)*(r-k);
150 }
151
152 // BEGIN CUT
153
154 int main()
155 {
156 auto t1 = clock();
157
158 std::freopen("../tests/subtask_6/175", "r", stdin);
159 std::freopen("6-175.out.txt", "w", stdout);
160
161 int n, m, k;
162 scanf("%d %d %d", &n, &m, &k);
163 std::vector<int> r(n), c(n);
164 for (int i = 0; i < n; i++)
165 {
166 scanf("%d %d", &r[i], &c[i]);
167 }
168
169 auto t2 = clock();
170
171 long long ans = take_photos(n, m, k, r, c);
172
173 auto t3 = clock();
174
175 // BEGIN SECRET
176 //puts("098d134608c94f7413faac591054ee35");
177 // END SECRET
178
179 printf("%lld\n", ans);
180
181 auto t4 = clock();
182
183 // reset console output
184 freopen("CON", "w", stdout);
185
186 //cout<<"ans = "<<ans<<"\n";
187
188 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
189 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
190 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
191
192 return 0;
193 }
194
195 // END CUT
196 /*
197 t2-t1 = 0.296
198 t3-t2 = 1.188
199 t4-t3 = 0
200
201 Process returned 0 (0x0) execution time : 1.750 s
202 Press any key to continue.
203 */
13 #define ub upper_bound
14 #define mp make_pair
15 #define test 0
16 #define TEST if(test)
17
18 using namespace std;
19
20 typedef long long ll;
21 typedef pair<int, int> pii;
22 typedef pair<ll, ll> pll;
23 typedef vector<int> vi;
24
25 const int MOD = 1000000007; // 998244353
26 const int INF = 2e9;
27 const ll INFLL = 1e12;
28 const int MAX_N = 100000;
29
30 int N, M, K;
31 vector<pii> vt;
32 vector<ll> C;
33 ll dp[MAX_N+1];
34
35 bool sf(pii a, pii b)
36 {
37 if(a.first==b.first)
38 {
39 return a.second>b.second;
40 }
41 return a.first<b.first;
42 }
43
44 struct S
45 {
46 ll a, b;
47 int idx;
48 };
49
50 vector<S> st;
51 int idx = 0;
52
53 void add(ll a, ll b, int i)
54 {
55 while(st.size()>=2)
56 {
57 S prv = st.back(); st.pop_back();
58 if((b-prv.b) * (prv.a - st.back().a) >=
59 (a-prv.a) * (prv.b - st.back().b))
60 {
61 if(idx==st.size()) idx--;
62 continue;
63 }
64 else
65 {
66 st.pb(prv);
67 break;
68 }
69 }
70 st.pb({a, b, i});
71 }
72
73 int cnt[MAX_N+1];
74
75 ll calc(ll x, int i)
76 {
77 while(idx+1<st.size())
78 {
79 if(st[idx+1].a * x + st[idx+1].b < st[idx].a * x + st[idx].b)
80 idx++;
81 else break;
82 }
83
84 cnt[i] = cnt[st[idx].idx]+1;
85 return st[idx].a * x + st[idx].b;
86 }
87
88 int solve(ll x)
CAPITOLUL 5. IOI 2016 724
89 {
90 st.clear();
91 idx = 0;
92 for(int i=0; i<vt.size(); i++)
93 {
94 add(-4LL * (ll)vt[i].first,
95 dp[i] - 2LL * C[i] + 2LL * (ll)vt[i].first * (ll)vt[i].first,
96 i);
97
98 dp[i+1] = 2LL * (ll)vt[i].second * (ll)vt[i].second +
99 calc((ll)vt[i].second, i+1) +
100 x;
101 }
102
103 return cnt[vt.size()];
104 }
105
106 long long take_photos(int n, int m, int k,
107 std::vector<int> r, std::vector<int> c)
108 {
109 N = n; M = m; K = k;
110 for(int i=0; i<N; i++)
111 {
112 vt.pb({min(r[i], c[i]), max(r[i], c[i]) + 1});
113 }
114
115 sort(vt.begin(), vt.end(), sf);
116
117 int mx = -1;
118 for(int i=0 ;i<N; i++)
119 {
120 if(mx>=vt[i].second)
121 {
122 vt[i].second = INF;
123 vt[i].first = INF;
124 }
125 else
126 mx = max(mx, vt[i].second);
127 }
128
129 sort(vt.begin(), vt.end());
130
131 while(!vt.empty() && vt.back().first==INF && vt.back().second==INF)
132 vt.pop_back();
133
134 C.pb(0LL);
135 for(int i=1; i<vt.size(); i++)
136 {
137 C.pb(max(0LL, (ll)(vt[i-1].second - vt[i].first)) *
138 max(0LL, (ll)(vt[i-1].second - vt[i].first)));
139 }
140
141 ll s = 0, e = (ll)M*(ll)M, mid;
142 while(s<e)
143 {
144 mid = (s+e)/2LL;
145 int t = solve(2LL*mid+1LL);
146 if(t<=K)
147 {
148 e = mid;
149 }
150 else
151 {
152 s = mid+1LL;
153 }
154 }
155
156 solve(2LL*s);
157
158 return (dp[vt.size()] - 2LL * s * (ll)K)/2LL;
159 }
160
161 // BEGIN CUT
162
163 int main()
164 {
CAPITOLUL 5. IOI 2016 725
25 ll a, b, c;
26 Line(ll a = 0, ll b = 0, ll c = 0) : a(a), b(b), c(c) {}
27 ll f(ll x){ return a * x + b; }
28 };
29
30 Line v[101010];
31 int pv, top;
32
33 ll f(int x, ll y){ return v[x].f(y); }
34
35 void init(){ pv = top = 0; }
36
37 int chk(const Line &a, const Line &b, const Line &c)
38 {
39 return (double)(a.b - b.b) / (b.a - a.a) >=
40 (double)(c.b - b.b) / (b.a - c.a);
41 }
42
43 void update(Line l)
44 {
45 while(top >= pv+2 && chk(v[top-2], v[top-1], l)) top--;
46 v[top++] = l;
47 }
48
49 p query(ll x)
50 {
51 while(pv+1 < top && v[pv].f(x) >= v[pv+1].f(x)) pv++;
52 return {v[pv].f(x), v[pv].c};
53 }
54 } cht;
55
56 void init(int N, int M, int K, const vector<int> &R, const vector<int> &C)
57 {
58 m = M, k = K; v.clear();
59 for(int i=0; i<N; i++)
60 v.emplace_back(max(R[i], C[i]) + 1, min(R[i], C[i]));
61
62 sort(all(v));
63
64 for(int i=0; i<N; i++)
65 {
66 while(n && a[n].y >= v[i].y) n--;
67 a[++n] = v[i];
68 }
69 }
70
71 int chk(ll c)
72 {
73 cht.init();
74 cht.update(CHT::Line(-2 * a[1].y * 2, a[1].y * a[1].y * 2, 0));
75
76 for(int i=1; i<=n; i++)
77 {
78 auto t = cht.query(a[i].x);
79 dp[i] = t.x + a[i].x * a[i].x * 2 + c;
80 cut[i] = cut[t.y] + 1;
81 ll ta = a[i+1].y, tb = max(0LL, a[i].x - a[i+1].y);
82 ll aa = -2 * a[i+1].y * 2;
83 ll bb = dp[i] + ta*ta*2 - tb*tb*2;
84 cht.update(CHT::Line(aa, bb, i));
85 }
86
87 return cut[n];
88 }
89
90 ll take_photos(int N, int M, int K,
91 vector<int> R, vector<int> C)
92 {
93 init(N, M, K, R, C);
94 int q = min(n, k);
95
96 ll l = 0, r = 1e15;
97 while(l < r)
98 {
99 ll m = l + r >> 1;
100 if(chk(m << 1 | 1) <= q) r = m;
CAPITOLUL 5. IOI 2016 727
101 else l = m + 1;
102 }
103
104 chk(r << 1);
105 return dp[n] / 2 - r * q;
106 }
107
108 // BEGIN CUT
109
110 int main()
111 {
112 auto t1 = clock();
113
114 std::freopen("../tests/subtask_6/175", "r", stdin);
115 std::freopen("6-175.out.txt", "w", stdout);
116
117 int n, m, k;
118 scanf("%d %d %d", &n, &m, &k);
119 std::vector<int> r(n), c(n);
120 for (int i = 0; i < n; i++)
121 {
122 scanf("%d %d", &r[i], &c[i]);
123 }
124
125 auto t2 = clock();
126
127 long long ans = take_photos(n, m, k, r, c);
128
129 auto t3 = clock();
130
131 // BEGIN SECRET
132 //puts("098d134608c94f7413faac591054ee35");
133 // END SECRET
134
135 printf("%lld\n", ans);
136
137 auto t4 = clock();
138
139 // reset console output
140 freopen("CON", "w", stdout);
141
142 //cout<<"ans = "<<ans<<"\n";
143
144 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
145 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
146 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
147
148 return 0;
149 }
150
151 // END CUT
152 /*
153 t2-t1 = 0.296
154 t3-t2 = 0.672
155 t4-t3 = 0
156
157 Process returned 0 (0x0) execution time : 2.630 s
158 Press any key to continue.
159 */
90 // BEGIN CUT
91
92 int main()
93 {
94 auto t1 = clock();
95
96 std::freopen("../tests/subtask_6/175", "r", stdin);
97 std::freopen("6-175.out.txt", "w", stdout);
98
99 int n, m, k;
100 scanf("%d %d %d", &n, &m, &k);
101 std::vector<int> r(n), c(n);
102 for (int i = 0; i < n; i++)
103 {
104 scanf("%d %d", &r[i], &c[i]);
105 }
106
107 auto t2 = clock();
108
109 long long ans = take_photos(n, m, k, r, c);
110
111 auto t3 = clock();
112
113 // BEGIN SECRET
114 //puts("098d134608c94f7413faac591054ee35");
115 // END SECRET
116
117 printf("%lld\n", ans);
118
119 auto t4 = clock();
120
121 // reset console output
122 freopen("CON", "w", stdout);
123
124 //cout<<"ans = "<<ans<<"\n";
125
126 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
127 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
128 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
129
130 return 0;
131 }
132
133 // END CUT
134 /*
135 t2-t1 = 0.312
136 t3-t2 = 0.797
137 t4-t3 = 0
138
139 Process returned 0 (0x0) execution time : 1.375 s
140 Press any key to continue.
141 */
21 };
22
23 std::deque<TLine> Lines;
24
25 TConvexHullTrick()
26 {
27 Lines.clear();
28 }
29
30 bool bad(const TLine& l1, const TLine& l2, const TLine& l3)
31 {
32 return (l1.b - l3.b) * (l2.a - l1.a) <
33 (l1.b - l2.b) * (l3.a - l1.a);
34 }
35
36 void add(ll a, ll b, int id)
37 {
38 TLine line(a, b, id);
39 while (Lines.size() >= 2 &&
40 bad(Lines[Lines.size()-2], Lines[Lines.size()-1], line))
41 {
42 Lines.pop_back();
43 }
44 Lines.push_back(line);
45 }
46
47 ll func(const TLine &d, ll x)
48 {
49 return d.a * x + d.b;
50 }
51
52 std::pair<ll, int> get(ll x)
53 {
54 while (Lines.size() >= 2 && func(Lines[0], x) > func(Lines[1], x))
55 {
56 Lines.pop_front();
57 }
58 return std::make_pair(func(Lines[0], x), Lines[0].id);
59 }
60 };
61
62
63 namespace Solver
64 {
65 const int N = 1e5 + 5;
66 std::pair<int, int> input[N];
67 int l[N], r[N];
68 int n, m, k;
69
70 ll dp[N];
71 int trace[N];
72
73 void process()
74 {
75 std::sort(input, input + n, [](const auto& x, const auto& y)
76 {
77 return x.first < y.first ||
78 (x.first == y.first && x.second > y.second);
79 });
80
81 int rmax = -1;
82 int cnt = 0;
83 for (int i = 0; i != n; ++i)
84 {
85 if (rmax < input[i].second)
86 {
87 rmax = input[i].second;
88 ++cnt;
89 l[cnt] = input[i].first;
90 r[cnt] = input[i].second;
91 }
92 }
93
94 n = cnt;
95 }
96
CAPITOLUL 5. IOI 2016 731
IOI 201531
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 ecare 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 e 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 ecare
sector se poate aa un num r oarecare de echipe. Unele sectoare pot 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 ecare echip , iar dup livrarea ultimului
suvenir urmeaz s revin în sectorul 0. De remarcat c unele echipe se pot aa î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 ecare moment Aman duce unul sau mai multe suvenire pân
ajunge la un sector în care se a 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.
31
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).
733
CAPITOLUL 6. IOI 2015 734
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
nal, 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 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 a 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 naliza
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 6. IOI 2015 735
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 rst 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: Let li be the optimal distance to deliver the rst 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 benet 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 dierent 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 6. IOI 2015 736
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.
59 {
60 int c, x, s;
61 c = _read();
62 while (c <= 32) c = _read();
63 x = 0;
64 s = 1;
65 if (c == ’-’)
66 {
67 s = -1;
68 c = _read();
69 }
70 while (c > 32)
71 {
72 x *= 10;
73 x += c - ’0’;
74 c = _read();
75 }
76 if (s < 0) x = -x;
77 return x;
78 }
79
80 int main()
81 {
82 _inputFile = fopen("../tests/subtask6/09", "rb");
83 _outputFile = fopen("boxes.out", "w");
84
85 int N, K, L, i;
86 N = _readInt();
87 K = _readInt();
88 L = _readInt();
89
90 int *p = (int*)malloc(sizeof(int) * (unsigned int)N);
91
92 for (i = 0; i < N; i++)
93 {
94 p[i] = _readInt();
95 }
96
97 fprintf(_outputFile, "%lld\n", delivery(N, K, L, p));
98 return 0;
99 }
100 // ----------------- start grader ---------------------
101 /*
102 execution time : 2.288 s
103 */
28 {
29 p[i] = l - p[i];
30 }
31 }
32
33 if (here == 0)
34 {
35 long long int sumleft = p[0], leftleft = -1;
36 int cur = k - 1;
37
38 for (int i = 1; i < n; ++i)
39 {
40 if (cur == 0)
41 {
42 sumleft += p[i - 1] + p[i] * 1LL;
43 cur = k - 1;
44 }
45 else
46 {
47 sumleft += p[i - 1] - p[i] * 1LL;
48 --cur;
49 }
50 }
51
52 sumleft += p[n - 1] * 1LL;
53
54 return sumleft;
55 }
56 else
57 if (here == n)
58 {
59 long long int sumright = p[here - 1], leftright = -1;
60 int cur = k - 1;
61
62 for (int i = here - 2; i >= 0; --i)
63 {
64 if (cur == 0)
65 {
66 sumright += p[i + 1] + p[i] * 1LL;
67 cur = k - 1;
68 }
69 else
70 {
71 sumright += p[i + 1] - p[i] * 1LL;
72 --cur;
73 }
74 }
75
76 sumright += p[0] * 1LL;
77
78 return sumright;
79 }
80
81 long long int sumleft = p[here - 1];
82 int cur = k - 1;
83
84 for (int i = here - 2; i >= 0; --i)
85 {
86 if (cur == 0)
87 {
88 sumleft += p[i + 1] + p[i] * 1LL;
89 cur = k - 1;
90 }
91 else
92 {
93 sumleft += p[i + 1] - p[i] * 1LL;
94 --cur;
95 }
96 }
97
98 sumleft += p[0] * 1LL;
99
100 long long int sumright = p[here];
101 cur = k - 1;
102
103 for (int i = here + 1; i < n; ++i)
CAPITOLUL 6. IOI 2015 739
104 {
105 if (cur == 0)
106 {
107 sumright += p[i - 1] + p[i] * 1LL;
108 cur = k - 1;
109 }
110 else
111 {
112 sumright += p[i - 1] - p[i] * 1LL;
113 --cur;
114 }
115 }
116
117 sumright += p[n - 1] * 1LL;
118
119 long long int curmin = sumleft + sumright;
120
121 if (k == 1)
122 return curmin;
123
124 long long int curval, min = 1e17;
125 int start;
126 for (int i = std::max(here - k + 1, 0);; ++i)
127 {
128 if (i >= here)
129 break;
130 if (i + k - 1 >= n)
131 break;
132
133 curval = l;
134
135 if (i != 0)
136 {
137 start = i - 1;
138
139 while (1)
140 {
141 if (start == i - 1)
142 curval += p[start] * 1LL;
143 else
144 curval += p[start] * 2LL;
145
146 if (start - k >= 0)
147 {
148 curval += p[start] - p[start - k] * 1LL;
149 start -= k;
150 }
151 else
152 {
153 curval += p[start] * 1LL;
154 break;
155 }
156 }
157 }
158 if (i + k < n)
159 {
160 start = i + k;
161
162 while (1)
163 {
164 if (start == i + k)
165 curval += p[start] * 1LL;
166 else
167 curval += p[start] * 2LL;
168
169 if (start + k < n)
170 {
171 curval += p[start] - p[start + k] * 1LL;
172 start += k;
173 }
174 else
175 {
176 curval += p[start] * 1LL;
177 break;
178 }
179 }
CAPITOLUL 6. IOI 2015 740
180 }
181
182 if (curval < min)
183 min = curval;
184 }
185
186 return std::min(curmin, min);
187 }
188
189 // ----------------- start grader ---------------------
190
191 static char _buffer[1024];
192
193 static int _currentChar = 0;
194 static int _charsNumber = 0;
195
196 static FILE *_inputFile, *_outputFile;
197
198 static inline int _read()
199 {
200 if (_charsNumber < 0)
201 {
202 exit(1);
203 }
204 if (!_charsNumber || _currentChar == _charsNumber)
205 {
206 _charsNumber = (int)fread(_buffer,
207 sizeof(_buffer[0]),
208 sizeof(_buffer),
209 _inputFile);
210 _currentChar = 0;
211 }
212 if (_charsNumber <= 0)
213 {
214 return -1;
215 }
216 return _buffer[_currentChar++];
217 }
218
219 static inline int _readInt()
220 {
221 int c, x, s;
222 c = _read();
223 while (c <= 32) c = _read();
224 x = 0;
225 s = 1;
226 if (c == ’-’)
227 {
228 s = -1;
229 c = _read();
230 }
231 while (c > 32)
232 {
233 x *= 10;
234 x += c - ’0’;
235 c = _read();
236 }
237 if (s < 0) x = -x;
238 return x;
239 }
240
241 int main()
242 {
243 _inputFile = fopen("../tests/subtask6/09", "rb");
244 _outputFile = fopen("boxes.out", "w");
245
246 int N, K, L, i;
247 N = _readInt();
248 K = _readInt();
249 L = _readInt();
250
251 int *p = (int*)malloc(sizeof(int) * (unsigned int)N);
252
253 for (i = 0; i < N; i++)
254 {
255 p[i] = _readInt();
CAPITOLUL 6. IOI 2015 741
256 }
257
258 fprintf(_outputFile, "%lld\n", delivery(N, K, L, p));
259 return 0;
260 }
261 // ----------------- start grader ---------------------
262 /*
263 execution time : 2.609 s
264 */
64 c = _read();
65 while (c <= 32) c = _read();
66 x = 0;
67 s = 1;
68 if (c == ’-’)
69 {
70 s = -1;
71 c = _read();
72 }
73 while (c > 32)
74 {
75 x *= 10;
76 x += c - ’0’;
77 c = _read();
78 }
79 if (s < 0) x = -x;
80 return x;
81 }
82
83 int main()
84 {
85 _inputFile = fopen("../tests/subtask6/09", "rb");
86 _outputFile = fopen("boxes.out", "w");
87
88 int N, K, L, i;
89 N = _readInt();
90 K = _readInt();
91 L = _readInt();
92
93 int *p = (int*)malloc(sizeof(int) * (unsigned int)N);
94
95 for (i = 0; i < N; i++)
96 {
97 p[i] = _readInt();
98 }
99
100 fprintf(_outputFile, "%lld\n", delivery(N, K, L, p));
101 return 0;
102 }
103 // ----------------- start grader ---------------------
104 /*
105 execution time : 2.578 s
106 */
30 registerTestlibCmd(argc, argv);
31
32 long long pans = readLong(ouf);
33 long long jans = readLong(ans);
34
35 if (pans != jans)
36 {
37 quitf(_wa, "Wrong answer: output = %lld, expected = %lld", pans, jans);
38 }
39 else
40 {
41 quitf(_ok, "Correct answer: answer = %lld", pans);
42 }
43 }
6.2 Scales
Problema 2 - Scales 100 de puncte
Author: Eryk Kopczynski (POL)
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, ecare corespunzând unui nou set de ³ase monede.
Programul t u trebuie sa implementeze funcµiile init ³i orderCoins. Pe parcursul ec 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 ecare 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 6. IOI 2015 744
Punctaj
Aceast problem nu are subprobleme. în schimb scorul t u va 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 rulat de mai multe ori ³i pe mai multe teste la ecare rulare. Fie r num rul
de rul ri ale programului t u. Acest num r este xat în datele de test. Dac programul t u nu
ordoneaz monezile corect la oricare test din oricare rulare, vei obµine 0 puncte. Altfel, ecare
rulare va 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 ecare test atunci x 0.) Scorul rul rii curente va
100
r xy ©51
, rotunjit în jos la dou zecimale.
în particular, dac programul face cel mult Q cânt riri pe ecare 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 6. IOI 2015 745
De exemplu, dac datele de intrare constau în dou teste unde monezile sunt ordonate 1 2 3 4
5 6 ³i 3 4 6 2 1 5 formatul datelor de intrare este urm torul:
21
2 3 4 5 6
3 4 6 2 1 5
Grader-ul de pe calculatorul vostru a³eaz ³irul trimis ca parametru de funcµia answer().
Timp maxim de executare/test: 1.0 secunde
Memorie: total 1500 MB
This is based on the well-known problem of ordering ve coins with 7 (binary) weighing. There
are 120 permutations and 128 possible sequences of seven answers, and it is indeed possible to
nd a strategy which always works.
In our problem, there are 720 possible answers, and with at most 6 ternary weighing, theore-
6
tically we could obtain 3 729 possible answers. The gap is very small, but it turns out that it
is again possible to nd 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 y.
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 6. IOI 2015 748
48 {
49 if (x < p[k][d]) x = 7;
50 if (y < p[k][d]) y = 7;
51 if (z < p[k][d]) z = 7;
52 }
53 if (x<y and x<z) return 0;
54 else return y<z ? 1 : 2;
55 } return -1;
56 }
57
58 int real()
59 {
60 int res;
61 if (t==1) res = getHeaviest(a, b, c);
62 if (t==2) res = getLightest(a, b, c);
63 if (t==3) res = getMedian(a, b, c);
64 if (t==4) res = getNextLightest(a, b, c, d);
65 if (res == a) return 0;
66 if (res == b) return 1;
67 if (res == c) return 2;
68 return -123; // ... !!!
69 }
70 };
71
72 vector<query> q;
73
74 struct node
75 {
76 query q;
77 node *ch[3];
78 set<int> s;
79 } *root;
80
81 bool make_tree(node* k, set<int> s)
82 {
83 k->s = s;
84 for (int i=0; i<3; i++)
85 if (!k->ch[i]) k->ch[i] = new node();
86 if (s.size() <= 1) return true;
87 for (int i=0; i<q.size(); i++)
88 {
89 set<int> r[3];
90 for (int e : s) r[q[i].moi(e)].insert(e);
91
92 if (max({r[0].size(), r[1].size(), r[2].size()}) -
93 min({r[0].size(), r[1].size(), r[2].size()}) < 2)
94 if (make_tree(k->ch[0], r[0]) and
95 make_tree(k->ch[1], r[1]) and
96 make_tree(k->ch[2], r[2]))
97 {
98 k->q = q[i];
99 return true;
100 }
101 } return false;
102 }
103
104 void init(int T)
105 {
106 for (int x=1; x<=6; x++)
107 for (int y=x+1; y<=6; y++)
108 for (int z=y+1; z<=6; z++)
109 {
110 q.emplace_back(1, x, y, z, -1);
111 q.emplace_back(2, x, y, z, -1);
112 q.emplace_back(3, x, y, z, -1);
113
114 for (int w=1; w<=6; w++)
115 if (x!=w and y!=w and z!=w)
116 q.emplace_back(4, x, y, z, w);
117 }
118
119 for (int i=1; i<720; i++)
120 {
121 copy(p[i-1]+1, p[i-1]+7, p[i]+1);
122 next_permutation(p[i]+1, p[i]+7);
123 }
CAPITOLUL 6. IOI 2015 750
124
125 set<int> st;
126 for (int i=0; i<720; i++) st.insert(i);
127 root = new node();
128 make_tree(root, st);
129 }
130
131 void orderCoins()
132 {
133 node *now = root;
134 while (now->s.size() > 1)
135 {
136 now = now->ch[now->q.real()];
137 }
138 int ans[6], *rans = p[ *now->s.begin() ];
139 for (int i=1; i<=6; i++)
140 ans[rans[i]-1] = i;
141 answer(ans);
142 }
143
144 // ------------- start grader --------------------
145
146 int main()
147 {
148 auto t1 = clock();
149
150 int T, i;
151
152 auto t2 = clock();
153
154 T = _getNumberOfTests();
155 init(T);
156
157 auto t3 = clock();
158
159 for (i = 1; i <= T; i++)
160 {
161 _initNewTest();
162 orderCoins();
163 }
164
165 auto t4 = clock();
166
167 // reset console output
168 freopen("CON", "w", stdout);
169
170 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
171 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
172 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
173
174 return 0;
175 }
176
177 // ------------- end grader --------------------
178 /*
179 t2-t1 = 0
180 t3-t2 = 0.578
181 t4-t3 = 0
182
183 Process returned 0 (0x0) execution time : 0.625 s
184 Press any key to continue.
185 */
87 {
88 if(pos.size() <= 1) return 1;
89 int cnt[4] = {0};
90 bool ok = 0;
91 for(auto& qq : lists)
92 {
93 cnt[1] = 0;
94 cnt[2] = 0;
95 cnt[3] = 0;
96
97 for(auto& ord : pos)
98 {
99 int res = qq.simask( *ord);
100 cnt[res]++;
101 if(cnt[res] > depmax[dep]) break;
102 }
103
104 if(cnt[1] > depmax[dep]) continue;
105 if(cnt[2] > depmax[dep]) continue;
106 if(cnt[3] > depmax[dep]) continue;
107 q = &qq;
108 for(int i = 1; i <= 3; i++)
109 {
110 go[i] = new Node();
111 go[i] -> dep = dep + 1;
112 }
113
114 for(auto ord : pos)
115 {
116 go[qq.simask( *ord)] -> pos.push_back(ord);
117 }
118
119 if(!go[1] -> init())
120 {
121 delete go[1];
122 continue;
123 }
124 if(!go[2] -> init())
125 {
126 delete go[2];
127 continue;
128 }
129 if(!go[3] -> init())
130 {
131 delete go[3];
132 continue;
133 }
134
135 ok = 1;
136 break;
137 }
138 return ok;
139 }
140
141 } *root;
142
143 void create()
144 {
145 for(int i = 1; i < 5; i++)
146 {
147 for(int j = i + 1; j < 6; j++)
148 {
149 for(int l = j + 1; l <= 6; l++)
150 {
151 for(int k = 1; k <= 6; k++)
152 {
153 lists.push_back(Query(i, j, l, k));
154 }
155 }
156 }
157 }
158 }
159
160 void init(int T)
161 {
162 create();
CAPITOLUL 6. IOI 2015 753
7 #include <bits/stdc++.h>
8
9 #define pii pair<int, int>
10 #define x first
11 #define y second
12
13 using namespace std;
14
15 vector<pair<int, vector<int> > > que;
16 vector<vector<int> > perm;
17
18 int ids[] = {0, 107, 107, 107, 49, 48, 46, 45, 44, 42, 38, 37, 35, 88,
19 95, 28, 67, 74, 15, 8, 40, 40, 85, 95, 28, 64, 74, 15, 11, 40, 40, 85,
20 88, 28, 64, 67, 15, 11, 33, 33, 31, 11, 9, 31, 11, 9, 10, 52, 52, 31,
21 24, 22, 31, 24, 22, 23, 52, 52, 72, 99, 79, 29, 18, 70, 29, 83, 5, 34,
22 8, 6, 34, 8, 6, 52, 7, 52, 34, 21, 19, 34, 21, 19, 52, 20, 52, 72, 103,
23 83, 32, 18, 69, 32, 79, 5, 41, 5, 3, 41, 5, 3, 55, 55, 4, 41, 18, 16,
24 41, 18, 16, 55, 55, 17, 103, 79, 83, 39, 21, 76, 39, 72, 8, 75, 55, 75,
25 65, 65, 55, 75, 18, 31, 68, 52, 68, 65, 65, 52, 18, 68, 31, 65, 65, 1,
26 8, 21, 58, 5, 75, 58, 96, 96, 55, 86, 86, 55, 96, 5, 31, 89, 89, 52,
27 86, 86, 52, 5, 89, 31, 86, 86, 1, 8, 8, 58, 5, 73, 58, 96, 16, 18, 58,
28 52, 68, 18, 52, 22, 68, 52, 65, 55, 96, 96, 55, 58, 8, 66, 86, 52, 21,
29 21, 86, 55, 75, 75, 75, 58, 75, 68, 68, 58, 75, 18, 34, 65, 52, 65, 68,
30 68, 52, 18, 65, 34, 19, 6, 55, 68, 68, 1, 75, 5, 55, 96, 96, 58, 89, 89,
31 58, 96, 5, 34, 86, 86, 52, 89, 89, 52, 5, 86, 34, 6, 6, 55, 89, 89, 1,
32 73, 5, 55, 16, 96, 18, 55, 52, 65, 18, 52, 19, 65, 52, 68, 96, 58, 96, 55,
33 55, 11, 63, 89, 52, 24, 24, 89, 75, 58, 75, 68, 58, 68, 75, 75, 58, 68,
34 21, 41, 65, 55, 65, 75, 75, 55, 21, 65, 41, 16, 3, 52, 68, 3, 52, 75,
35 75, 1, 89, 89, 58, 96, 96, 58, 89, 8, 41, 86, 86, 55, 96, 96, 55, 8, 86,
36 41, 3, 3, 52, 66, 3, 52, 96, 96, 1, 55, 52, 65, 16, 89, 21, 52, 21, 16,
37 65, 55, 75, 89, 58, 89, 52, 52, 11, 63, 96, 55, 24, 24, 96, 68, 58, 68, 0};
38 int mx = 0;
39 int zzz;
40
41 int dfs(int u, vector<int> vec, int lv)
42 {
43 if(vec.size() == 1) return vec[0];
44 mx = max(mx, u);
45 for(int ii = ids[u];;)
46 {
47 auto& z = que[ii];
48 vector<int> Mp[6];
49 int abc;
50 if(z.x == 0)
51 abc = getHeaviest(z.y[0]+1, z.y[1]+1, z.y[2]+1);
52 if(z.x == 1)
53 abc = getLightest(z.y[0]+1, z.y[1]+1, z.y[2]+1);
54 if(z.x == 2)
55 abc = getMedian(z.y[0]+1, z.y[1]+1, z.y[2]+1);
56 if(z.x == 3)
57 abc = getNextLightest(z.y[0]+1, z.y[1]+1, z.y[2]+1, z.y[3]+1);
58
59 for(int v : vec)
60 {
61 vector<pii> val;
62 for(int i = 0; i < 3; ++i)
63 val.emplace_back(perm[v][z.y[i]], z.y[i]);
64
65 sort(val.begin(), val.end());
66
67 if(z.x == 0)
68 Mp[val[2].y].emplace_back(v);
69 else
70 if(z.x == 1)
71 Mp[val[0].y].emplace_back(v);
72 else
73 if(z.x == 2)
74 Mp[val[1].y].emplace_back(v);
75 else
76 {
77 bool st = false;
78 for(int i = 0; i < 3; ++i)
79 {
80 if(val[i].x > perm[v][z.y[3]])
81 {
82 Mp[val[i].y].emplace_back(v);
CAPITOLUL 6. IOI 2015 755
83 st = true;
84 break;
85 }
86 }
87
88 if(!st) Mp[val[0].y].emplace_back(v);
89 }
90
91 }
92
93 int step = 0;
94 for(int i = 0; i < 6; ++i) if(Mp[i].size())
95 {
96 step++;
97 if(i == abc-1)
98 return dfs(u*3 + step, Mp[i], lv / 3);
99 }
100 }
101
102 return false;
103 }
104
105 int nth = 6;
106
107 void init(int T)
108 {
109 for(int i = 0; i < (1 << nth); ++i)
110 {
111 vector<int> vec;
112 for(int j = 0; j < nth; ++j) if(i >> j & 1)
113 vec.emplace_back(j);
114 if(vec.size() == 3)
115 for(int j = 0; j < 3; ++j) que.emplace_back(j, vec);
116 if(vec.size() == 4)
117 {
118 for(int i = 0; i < 4; ++i)
119 {
120 vector<int> ret;
121 for(int j = 0; j < 4; ++j)
122 if(i != j)
123 ret.emplace_back(vec[j]);
124 ret.emplace_back(vec[i]);
125 que.emplace_back(3, ret);
126 }
127 }
128 }
129
130 vector<int> now;
131 for(int i = 0; i < nth; ++i)
132 now.emplace_back(i+1);
133 do
134 {
135 perm.emplace_back(now);
136 } while(next_permutation(now.begin(), now.end()));
137 }
138
139 void orderCoins()
140 {
141 int* ans = new int[6];
142 vector<int> zz;
143 for(int i = 0; i < perm.size(); ++i)
144 zz.emplace_back(i);
145 int k = dfs(0, zz, 2187);
146 for(int i = 0; i < 6; ++i)
147 ans[perm[k][i]-1] = i+1;
148 answer(ans);
149 }
150
151 // ------------- start grader --------------------
152
153 int main()
154 {
155 auto t1 = clock();
156
157 int T, i;
158
CAPITOLUL 6. IOI 2015 756
6.3 Teams
Problema 3 - Teams 100 de puncte
CAPITOLUL 6. IOI 2015 757
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 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 ind 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 ecare 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 ecare î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 ecare 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 ecare zi.
M : num rul de proiecte pentru aceast zi.
K : un ³ir de lungime M conµinând dimensiunile cerute pentru echip ecarui 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 ecare 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 6. IOI 2015 758
We can nd the appropriate corner cl such that there are at least k allowed points in a rectangle
0, k 0, cl in time O l log n (we test sequentially c1 , c2 , ..., each time asking about points in
some rectangle and summing them up).
Once we found cl , we know that the y coordinate of our new corner will be somewhere between
2
y cl1 and y cl . We can binary search for the exact y in time O log n.
Ó
O n log n preprocessing, O m n log n amortized query
We Ócan combine the two solutions above to obtain
Ó
a better bound: - we run the rst solution
if m % n, - we run the second solution if m & n.
O n log n preprocessing, O m log n query
2
If we store the corners in some kind of binary search tree and decompose the forbidden area
into rectangles (picture) so that each corner knows how (is responsible for) many points are there
CAPITOLUL 6. IOI 2015 759
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.
Another O m2 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 benecial to take index
i than j , while computing the minimum in the formula for Dk . Then, for any l % k , it's also more
benecial 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 benecial. 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 nd W i, j in time
O log n.
Let B Dj Di .
We need to nd 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 rst point with x
¬
' x and last with x & xinA, mid
¬
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 6. IOI 2015 760
71 init(t[x].l, l, m);
72 init(t[x].r, m + 1, r);
73 }
74
75 void init(int N, int A[], int B[])
76 {
77 n = N;
78 for(int i = 1; i <= n; i++)
79 {
80 a[i] = ii(B[i - 1], A[i - 1]);
81 }
82
83 sort(a + 1, a + n + 1);
84
85 vector < ii > vs;
86 for(int i = 1; i <= n; i++)
87 vs.push_back(ii(a[i].second, i));
88
89 sort(vs.begin(), vs.end());
90
91 int ptr = 0;
92 ps[0] = cnt++;
93 init(ps[0], 1, n);
94 for(int i = 1; i <= n; i++)
95 {
96 ps[i] = ps[i - 1];
97 while(ptr < vs.size() and vs[ptr].first <= i)
98 {
99 ps[i] = insert(ps[i], 1, n, vs[ptr].second);
100 ptr++;
101 }
102 }
103 del = cnt++;
104 init(del, 1, n);
105 }
106
107 void push(int x)
108 {
109 if(t[x].lazy)
110 {
111 t[t[x].l].x = t[t[t[x].lazy].l].x;
112 t[t[x].r].x = t[t[t[x].lazy].r].x;
113 t[t[x].l].lazy = t[t[x].lazy].l;
114 t[t[x].r].lazy = t[t[x].lazy].r;
115 t[x].lazy = 0;
116 }
117 }
118
119 int get(int x, int del, int l, int r, int x1, int x2, int k)
120 {
121 if(x1 <= l and r <= x2 and t[x].x - t[del].x <= k)
122 {
123 t[del].lazy = x;
124 int ret = t[x].x - t[del].x;
125 t[del].x += ret;
126 return ret;
127 }
128
129 if(x2 < l or r < x1 or l == r)
130 return 0;
131 int m = l + r >> 1;
132 push(del);
133 int lf = get(t[x].l, t[del].l, l, m, x1, x2, k);
134 if(lf == k)
135 {
136 t[del].x = t[t[del].l].x + t[t[del].r].x;
137 return k;
138 }
139 k -= lf;
140 int rf = get(t[x].r, t[del].r, m + 1, r, x1, x2, k);
141 t[del].x = t[t[del].l].x + t[t[del].r].x;
142 return lf + rf;
143 }
144
145 void clear(int x)
146 {
CAPITOLUL 6. IOI 2015 762
223 }
224 if (s < 0) x = -x;
225 return x;
226 }
227
228 int main()
229 {
230 _inputFile = fopen("../tests/72", "rb");
231 _outputFile = fopen("teams.out", "w");
232
233 int N;
234 N = _readInt();
235
236 int *A = (int*)malloc(sizeof(int)*(unsigned int)N);
237 int *B = (int*)malloc(sizeof(int)*(unsigned int)N);
238
239 for (int i = 0; i < N; ++i)
240 {
241 A[i] = _readInt();
242 B[i] = _readInt();
243 }
244
245 init(N, A, B);
246
247 int Q;
248 Q = _readInt();
249 for (int i = 0; i < Q; ++i)
250 {
251 int M;
252 M = _readInt();
253 int *K = (int*)malloc(sizeof(int)*(unsigned int)M);
254 for (int j = 0; j < M; ++j)
255 {
256 K[j] = _readInt();
257 }
258 fprintf(_outputFile,"%d\n", can(M, K));
259 }
260
261 return 0;
262 }
263 // --------------- end grader ----------------------
264 /*
265 execution time : 3.156 s
266 */
29
30 int qry(int a, int b, int tl, int tr, int l, int r)
31 {
32 if(tl > r || tr < l) return 0;
33 if(tl >= l && tr <= r) return s[a]-s[b];
34 return qry(L[a],L[b],tl,tm,l,r) + qry(R[a],R[b],tm+1,tr,l,r);
35 }
36
37 int bs(int a, int b, int tl, int tr, int k)
38 {
39 if(tl == tr) return tl;
40 if(s[ L[a] ] - s[ L[b] ] < k)
41 return bs(R[a],R[b],tm+1,tr,k-(s[ L[a] ] - s[ L[b] ]));
42 return bs(L[a],L[b],tl,tm,k);
43 }
44
45 #define mp make_pair
46 #define st first
47 #define nd second
48 int n;
49
50 int can(int m, int *K)
51 {
52 int t,i,l,md,r,x,y,z,las,req,ex;
53 stack < pair < int , pair<int,int> > > S;
54 S.push(mp(0,mp(mx,0)));
55 sort(K , K+m);
56 for(i=0;i<m;i++)
57 {
58 las = req = x = K[i];
59 ex = 0;
60 for(;;)
61 {
62 y = S.top().st;
63 z = S.top().nd.st;
64 if(z < las)
65 {
66 S.pop();
67 continue;
68 }
69 if(z == las)
70 {
71 ex += S.top().nd.nd;
72 S.pop();
73 continue;
74 }
75
76 l = bs(root[x],root[y],1,n,
77 req+ex+qry(root[x],
78 root[y],1,n,1,las-1) );
79
80 if(l >= (t = S.top().nd.st))
81 {
82 req -= qry(root[x],root[y],1,n,las,t-1) - ex;
83 las = t;
84 ex = S.top().nd.nd;
85 S.pop();
86 continue;
87 }
88 else
89 {
90 req -= qry(root[x],root[y],1,n,las,l)-ex;
91 if(req > 0) return 0;
92 ex = req + qry(root[x],root[y],1,n,l,l);
93 S.push(mp(x,mp(l,ex)));
94 break;
95 }
96 }
97 }
98
99 return 1;
100 }
101
102 vector < int > V[mx];
103 void init(int ss, int *a, int *b)
104 {
CAPITOLUL 6. IOI 2015 765
105 n = ss;
106 int i,j,p=0;
107 for(i=0;i<n;i++) V[ a[i] ].push_back(b[i]);
108 for(i=1;i<=n;i++)
109 {
110 for(j=0;j<V[i].size();j++)
111 p = up(p,1,n,V[i][j]);
112 root[i] = p;
113 }
114 }
115
116 // --------------- begin grader ----------------------
117
118 static char _buffer[1024];
119 static int _currentChar = 0;
120 static int _charsNumber = 0;
121 static FILE *_inputFile, *_outputFile;
122
123 static inline int _read()
124 {
125 if (_charsNumber < 0)
126 {
127 exit(1);
128 }
129
130 if (!_charsNumber || _currentChar == _charsNumber)
131 {
132 _charsNumber = (int)fread(_buffer,
133 sizeof(_buffer[0]),
134 sizeof(_buffer),
135 _inputFile);
136 _currentChar = 0;
137 }
138
139 if (_charsNumber <= 0)
140 {
141 return -1;
142 }
143
144 return _buffer[_currentChar++];
145 }
146
147 static inline int _readInt()
148 {
149 int c, x, s;
150 c = _read();
151 while (c <= 32) c = _read();
152 x = 0;
153 s = 1;
154 if (c == ’-’)
155 {
156 s = -1;
157 c = _read();
158 }
159 while (c > 32)
160 {
161 x *= 10;
162 x += c - ’0’;
163 c = _read();
164 }
165 if (s < 0) x = -x;
166 return x;
167 }
168
169 int main()
170 {
171 _inputFile = fopen("../tests/72", "rb");
172 _outputFile = fopen("teams.out", "w");
173
174 int N;
175 N = _readInt();
176
177 int *A = (int*)malloc(sizeof(int)*(unsigned int)N);
178 int *B = (int*)malloc(sizeof(int)*(unsigned int)N);
179
180 for (int i = 0; i < N; ++i)
CAPITOLUL 6. IOI 2015 766
181 {
182 A[i] = _readInt();
183 B[i] = _readInt();
184 }
185
186 init(N, A, B);
187
188 int Q;
189 Q = _readInt();
190 for (int i = 0; i < Q; ++i)
191 {
192 int M;
193 M = _readInt();
194 int *K = (int*)malloc(sizeof(int)*(unsigned int)M);
195 for (int j = 0; j < M; ++j)
196 {
197 K[j] = _readInt();
198 }
199 fprintf(_outputFile,"%d\n", can(M, K));
200 }
201
202 return 0;
203 }
204 // --------------- end grader ----------------------
205 /*
206 execution time : 2.250 s
207 */
46 tree[cnd].l = tree.size();
47 tree.eb(0, 0, 0);
48 expand_tree(s, m, k, tree[pnd].l, tree[cnd].l);
49 }
50 else
51 {
52 tree[cnd].l = tree[pnd].l;
53 tree[cnd].r = tree.size();
54 tree.eb(0, 0, 0);
55 expand_tree(m+1, e, k, tree[pnd].r, tree[cnd].r);
56 }
57 }
58
59 void init(int N, int A[], int B[])
60 {
61 n = N;
62 for(int i = 0; i < n; i++)
63 {
64 arr[i] = make_pair(A[i], B[i]);
65 num.eb(B[i]);
66 numx.eb(A[i]);
67 }
68
69 sort(all(num));
70 sort(all(numx));
71 sort(arr, arr+n, [](pii a, pii b)
72 {
73 if(a.se == b.se) return a.fi < b.fi;
74 return a.se < b.se;
75 });
76 for(int i = 0; i < n; i++)
77 {
78 arr[i].se = i + 1;
79 }
80 sort(arr, arr+n);
81 tree.eb(0, 0, 0);
82 for(int i = 0; i < n; i++)
83 {
84 root[i+1] = tree.size();
85 tree.eb(0, 0, 0);
86 expand_tree(1, n, arr[i].se, root[i], root[i+1]);
87 }
88 return;
89 }
90
91 int cal(int s, int e, int l, int r, int pnd, int cnd)
92 {
93 if(s > r || e < l || l > r) return 0;
94 if(s >= l && e <= r) return tree[cnd].val - tree[pnd].val;
95 int m = s + e >> 1;
96 return cal(s, m, l, r, tree[pnd].l, tree[cnd].l)
97 + cal(m+1, e, l, r, tree[pnd].r, tree[cnd].r);
98 }
99
100 int get_r(int s, int e, int cnt, int pnd, int cnd)
101 {
102 if(s == e) return s;
103 int m = s + e >> 1,
104 lcnt = tree[tree[cnd].l].val - tree[tree[pnd].l].val;
105 if(lcnt >= cnt)
106 return get_r(s, m, cnt, tree[pnd].l, tree[cnd].l);
107 else
108 return get_r(m+1, e, cnt - lcnt, tree[pnd].r, tree[cnd].r);
109 }
110
111 int can(int M, int K[])
112 {
113 ll temp = 0;
114 for(int i = 0; i < M; i++) temp += K[i];
115 if(temp > n) return 0;
116
117 sort(K, K+M);
118 stack <pii> stk;
119
120 stk.em(0, n+1);
121 for(int i = 0; i < M; i++)
CAPITOLUL 6. IOI 2015 768
122 {
123 int last = lower_bound(all(num), K[i]) - num.begin() + 1,
124 cnt = K[i];
125 int rx = upper_bound(all(numx), K[i]) - numx.begin();
126 while(!stk.empty() && stk.top().se < last) stk.pop();
127 while(!stk.empty())
128 {
129 int x = stk.top().fi, y = stk.top().se;
130 int temp = cal(1, n, last, y, root[x], root[rx]);
131 if(temp < cnt)
132 {
133 cnt -= temp;
134 last = y + 1;
135 stk.pop();
136 }
137 else
138 {
139 int l = cal(1, n, 1, last - 1, root[x], root[rx]);
140 int ny = get_r(1, n, l + cnt, root[x], root[rx]);
141 stk.em(rx, ny);
142 break;
143 }
144 }
145
146 if(stk.empty()) return 0;
147 }
148 return 1;
149 }
150 // --------------- begin grader ----------------------
151
152 static char _buffer[1024];
153 static int _currentChar = 0;
154 static int _charsNumber = 0;
155 static FILE *_inputFile, *_outputFile;
156
157 static inline int _read()
158 {
159 if (_charsNumber < 0)
160 {
161 exit(1);
162 }
163
164 if (!_charsNumber || _currentChar == _charsNumber)
165 {
166 _charsNumber = (int)fread(_buffer,
167 sizeof(_buffer[0]),
168 sizeof(_buffer),
169 _inputFile);
170 _currentChar = 0;
171 }
172
173 if (_charsNumber <= 0)
174 {
175 return -1;
176 }
177
178 return _buffer[_currentChar++];
179 }
180
181 static inline int _readInt()
182 {
183 int c, x, s;
184 c = _read();
185 while (c <= 32) c = _read();
186 x = 0;
187 s = 1;
188 if (c == ’-’)
189 {
190 s = -1;
191 c = _read();
192 }
193 while (c > 32)
194 {
195 x *= 10;
196 x += c - ’0’;
197 c = _read();
CAPITOLUL 6. IOI 2015 769
198 }
199 if (s < 0) x = -x;
200 return x;
201 }
202
203 int main()
204 {
205 _inputFile = fopen("../tests/72", "rb");
206 _outputFile = fopen("teams.out", "w");
207
208 int N;
209 N = _readInt();
210
211 int *A = (int*)malloc(sizeof(int)*(unsigned int)N);
212 int *B = (int*)malloc(sizeof(int)*(unsigned int)N);
213
214 for (int i = 0; i < N; ++i)
215 {
216 A[i] = _readInt();
217 B[i] = _readInt();
218 }
219
220 init(N, A, B);
221
222 int Q;
223 Q = _readInt();
224 for (int i = 0; i < Q; ++i)
225 {
226 int M;
227 M = _readInt();
228 int *K = (int*)malloc(sizeof(int)*(unsigned int)M);
229 for (int j = 0; j < M; ++j)
230 {
231 K[j] = _readInt();
232 }
233 fprintf(_outputFile,"%d\n", can(M, K));
234 }
235
236 return 0;
237 }
238 // --------------- end grader ----------------------
239 /*
240 execution time : 6.203 s
241 */
6.4 Horses
Problema 4 - Horses 100 de puncte
Author: Mansur Kutybayev (KAZ)
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 ecare an inuenµa cre³terea hergheliei. Pentru ecare an i Mansur memoreaz
un coecient 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 vânduµi numai la sfâr³itul unui an. Pentru ecare an i, Mansur memoreaz un
întreg pozitiv Y i: preµul unui cal la sfâr³itul anului i. La sfâr³itul ec rui an era posibil s vinzi
oricâµi cai, ecare 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 i
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 modic ri. Fiecare
modicare va schimba e una dintre valorile X i, e una dintre valorile Y i. Dup ecare
modicare el te întreab dinnou care e suma cea mai mare pe care o poate obµine din vânzarea
cailor. Modic rile lui Manur sunt cumulative: ecare r spuns trebuie s µin cont de toate
modic rile precedente. Reµineµi c oricare dintre valorile X i sau Y i ar putea modicat
de mai multe ori.
R spunsul lui Mansur poate 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. Protul total va 2 Y 1 8.
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 6. IOI 2015 771
Cerinµ
Se dau N , X , Y , ³i lista de modic ri. înainte de prima modicare ³i dup ecare modicare,
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 coecientul 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 specic valorile iniµiale date de Mansur (înainte de orice
modicare).
Dup ce apelul init se încheie, ³irurile X ³i Y r mân valabile, ³i poµi modica conµi-
nutul 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 modicare, 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 modicare, modulo 10 7.
9
Se asigur c atât valorile iniµiale cât ³i cele modicate 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 M .
Subprobleme
Grader-ul de pe calculatorul t u a³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 prot 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.
Prot of i-th day: x1 x2 ... xi yi
Prot 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 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
prot.
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
75
76 join(node);
77 }
78
79 int init(int N, int X[], int Y[])
80 {
81 n = N;
82 for (int i = 0; i < n; i++)
83 x[i] = (ll)X[i], y[i] = (ll)Y[i];
84 build(1, 0, n-1);
85
86 return (int)tree[1].maiorp;
87 }
88
89 int updateX(int pos, int val)
90 {
91 x[pos] = (ll)val;
92 upd(1, 0, n-1, pos);
93
94 return (int)tree[1].maiorp;
95 }
96
97 int updateY(int pos, int val)
98 {
99 y[pos] = (ll)val;
100 upd(1, 0, n-1, pos);
101
102 return (int)tree[1].maiorp;
103 }
104
105 // ------------------ begin grader ----------------
106
107 static char _buffer[1024];
108 static int _currentChar = 0;
109 static int _charsNumber = 0;
110 static FILE *_inputFile, *_outputFile;
111
112 static inline int _read()
113 {
114 if (_charsNumber < 0)
115 {
116 exit(1);
117 }
118 if (!_charsNumber || _currentChar == _charsNumber)
119 {
120 _charsNumber = (int)fread(_buffer,
121 sizeof(_buffer[0]),
122 sizeof(_buffer),
123 _inputFile);
124 _currentChar = 0;
125 }
126 if (_charsNumber <= 0)
127 {
128 return -1;
129 }
130 return _buffer[_currentChar++];
131 }
132
133 static inline int _readInt()
134 {
135 int c, x, s;
136 c = _read();
137 while (c <= 32) c = _read();
138 x = 0;
139 s = 1;
140 if (c == ’-’)
141 {
142 s = -1;
143 c = _read();
144 }
145 while (c > 32)
146 {
147 x *= 10;
148 x += c - ’0’;
149 c = _read();
150 }
CAPITOLUL 6. IOI 2015 775
21 public:
22 int all;
23 int left;
24 int right;
25 int sell;
26 int prod;
27 int ans;
28 };
29
30 vector<node> tree;
31 vector<int> a, b;
32 int n;
33
34 void pull(int x, int z)
35 {
36 tree[x].all = min((long long) tree[x + 1].all * tree[z].all, inf);
37 tree[x].prod = mul(tree[x + 1].prod, tree[z].prod);
38 if (tree[x + 1].sell > (long long) tree[x + 1].right * tree[z].left)
39 {
40 tree[x].ans = tree[x + 1].ans;
41 tree[x].sell = tree[x + 1].sell;
42 tree[x].left = tree[x + 1].left;
43 tree[x].right = min((long long) tree[x + 1].right * tree[z].all, inf);
44 }
45 else
46 {
47 tree[x].ans = mul(tree[z].ans, tree[x + 1].prod);
48 tree[x].sell = tree[z].sell;
49 tree[x].left = min((long long) tree[x + 1].all * tree[z].left, inf);
50 tree[x].right = tree[z].right;
51 }
52 }
53
54 void build(int x, int l, int r)
55 {
56 if (l == r)
57 {
58 tree[x].all = a[l];
59 tree[x].prod = a[l];
60 tree[x].ans = mul(a[l], b[l]);
61 tree[x].sell = b[l];
62 tree[x].left = min((long long) a[l] * b[l], inf);
63 tree[x].right = 1;
64 }
65 else
66 {
67 int y = (l + r) >> 1, z = x + ((y - l + 1) << 1);
68 build(x + 1, l, y);
69 build(z, y + 1, r);
70 pull(x, z);
71 }
72 }
73
74 void modify(int x, int l, int r, int p)
75 {
76 if (l == r)
77 {
78 tree[x].all = a[l];
79 tree[x].prod = a[l];
80 tree[x].ans = mul(a[l], b[l]);
81 tree[x].sell = b[l];
82 tree[x].left = min((long long) a[l] * b[l], inf);
83 tree[x].right = 1;
84 }
85 else
86 {
87 int y = (l + r) >> 1, z = x + ((y - l + 1) << 1);
88 if (p <= y)
89 {
90 modify(x + 1, l, y, p);
91 }
92 else
93 {
94 modify(z, y + 1, r, p);
95 }
96 pull(x, z);
CAPITOLUL 6. IOI 2015 777
97 }
98 }
99
100 int init(int N, int X[], int Y[])
101 {
102 n = N;
103 for (int i = 0; i < n; ++i)
104 {
105 a.push_back(X[i]);
106 b.push_back(Y[i]);
107 }
108 tree.resize(n * 2 - 1);
109 build(0, 0, n - 1);
110 return tree[0].ans;
111 }
112
113 int updateX(int pos, int val)
114 {
115 a[pos] = val;
116 modify(0, 0, n - 1, pos);
117 return tree[0].ans;
118 }
119
120 int updateY(int pos, int val)
121 {
122 b[pos] = val;
123 modify(0, 0, n - 1, pos);
124 return tree[0].ans;
125 }
126
127 // ------------------ begin grader ----------------
128
129 static char _buffer[1024];
130 static int _currentChar = 0;
131 static int _charsNumber = 0;
132 static FILE *_inputFile, *_outputFile;
133
134 static inline int _read()
135 {
136 if (_charsNumber < 0)
137 {
138 exit(1);
139 }
140 if (!_charsNumber || _currentChar == _charsNumber)
141 {
142 _charsNumber = (int)fread(_buffer,
143 sizeof(_buffer[0]),
144 sizeof(_buffer),
145 _inputFile);
146 _currentChar = 0;
147 }
148 if (_charsNumber <= 0)
149 {
150 return -1;
151 }
152 return _buffer[_currentChar++];
153 }
154
155 static inline int _readInt()
156 {
157 int c, x, s;
158 c = _read();
159 while (c <= 32) c = _read();
160 x = 0;
161 s = 1;
162 if (c == ’-’)
163 {
164 s = -1;
165 c = _read();
166 }
167 while (c > 32)
168 {
169 x *= 10;
170 x += c - ’0’;
171 c = _read();
172 }
CAPITOLUL 6. IOI 2015 778
97 n=N;
98 for (int i=0; i<N; i++)
99 {
100 x[i] = X[i];
101 y[i] = Y[i];
102 }
103 ST.build(0, N-1, 1);
104 LL p = ST.opt(), prod = ST.ask(p, 0, N-1, 1);
105 LL ans = (prod * y[p])%MOD;
106 return( (int) ans);
107 }
108
109 int updateX(int pos, int val)
110 {
111 x[pos]=val;
112 ST.upd(pos, 0, n-1, 1);
113 LL p = ST.opt(), prod = ST.ask(p, 0, n-1, 1);
114 LL ans = (prod * y[p])%MOD;
115 return( (int) ans);
116 }
117
118 int updateY(int pos, int val)
119 {
120 y[pos]=val;
121 ST.upd(pos, 0, n-1, 1);
122 LL p = ST.opt(), prod = ST.ask(p, 0, n-1, 1);
123 LL ans = (prod * y[p])%MOD;
124 return( (int) ans);
125 }
126
127 // ------------------ begin grader ----------------
128
129 static char _buffer[1024];
130 static int _currentChar = 0;
131 static int _charsNumber = 0;
132 static FILE *_inputFile, *_outputFile;
133
134 static inline int _read()
135 {
136 if (_charsNumber < 0)
137 {
138 exit(1);
139 }
140 if (!_charsNumber || _currentChar == _charsNumber)
141 {
142 _charsNumber = (int)fread(_buffer,
143 sizeof(_buffer[0]),
144 sizeof(_buffer),
145 _inputFile);
146 _currentChar = 0;
147 }
148 if (_charsNumber <= 0)
149 {
150 return -1;
151 }
152 return _buffer[_currentChar++];
153 }
154
155 static inline int _readInt()
156 {
157 int c, x, s;
158 c = _read();
159 while (c <= 32) c = _read();
160 x = 0;
161 s = 1;
162 if (c == ’-’)
163 {
164 s = -1;
165 c = _read();
166 }
167 while (c > 32)
168 {
169 x *= 10;
170 x += c - ’0’;
171 c = _read();
172 }
CAPITOLUL 6. IOI 2015 781
21 for(int kk=0;kk<argc;kk++)
22 cout<<argv[kk]<<"\n";
23 cout<<"----------------------\n";
24
25 registerChecker("horses", argc, argv);
26 compareRemainingLines(1); // incepand cu linia nr 1
27 return 0;
28 }
6.5 Sorting
Problema 5 - Sorting 100 de puncte
Author: Weidong Hu (CHN)
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 modica ³irul într-o serie de runde. în ecare 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 e 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 ecare 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 ec 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 modic ³irul.
CAPITOLUL 6. IOI 2015 783
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 modic secvenµa.
Cerinµa
i se d ³irul S , num rul M ³i ³irurile de indici X ³i Y . Determin o secvenµ de interschim-
b 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 e cea mai scurt posibil .
Trebuie s implementezi funcµia findSwapPairs:
findSwapPairs(N, S, M, X, Y, P, Q) - Aceast funcµie va apelat de grader
exact 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 sec-
venµ 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 ecare i cuprins
între 0 ³i R 1 inclusiv, indicii pe care Aizhan trebuie s îi aleag în runda sunt me-
moraµi în P i ³i Qi. Poµi presupune c tablourile P ³i Q au deja alocate câte M
elemente ecare.
Aceast funcµie trebuie s returneze valoarea lui R (denit mai sus).
Subprobleme
CAPITOLUL 6. IOI 2015 784
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 Bobâs 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 6. IOI 2015 785
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
dierence objects, the sequence of operations can be separated. Let t be the number of rounds
Alice takes. It can be viewed as Bob rst 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 rst 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 rst nd 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.
16 int qayl_qan()
17 {
18 int q=0;
19 for(int i=0;i<n;i++)
20 rev_ps[ps[i]]=i;
21 for(int i=0;i<n;i++)
22 {
23 if(ps[rev_ps[i]]==ps[i])
24 continue;
25 int e=ps[i];
26 swap(ps[rev_ps[i]],ps[i]);
27 q++;
28 swap(rev_ps[i],rev_ps[e]);
29 }
30 return q;
31 }
32
33 int stug(int e)
34 {
35 for(int i=0;i<n;i++)
36 ps[i]=s[i];
37 for(int i=0;i<=e;i++)
38 swap(ps[x[i]],ps[y[i]]);
39 if(qayl_qan()<=e+1)
40 return 1;
41 else
42 return 0;
43 }
44
45 int bin(int l,int r)
46 {
47 if(l==r)
48 return r;
49
50 int mid=(l+r)/2;
51
52 if(stug(mid))
53 bin(l,mid);
54 else
55 bin(mid+1,r);
56 }
57
58 int findSwapPairs(int N, int S[], int M, int X[], int Y[], int P[], int Q[])
59 {
60 if(M>=N)
61 M=N-1;
62 for(int i=0;i<N;i++)
63 s[i]=S[i];
64 for(int i=0;i<M;i++)
65 {
66 x[i]=X[i];
67 y[i]=Y[i];
68 }
69 n=N;
70 for(int i=0;i<n;i++)
71 ps[i]=s[i];
72 if(qayl_qan()==0)
73 return 0;
74 int t=bin(0,M-1);
75 t++;
76 for(int i=0;i<n;i++)
77 ps[i]=s[i];
78 for(int i=0;i<t;i++)
79 swap(ps[x[i]],ps[y[i]]);
80 for(int i=0;i<n;i++)
81 rev_ps[ps[i]]=i;
82 for(int i=0;i<n;i++)
83 {
84 if(ps[rev_ps[i]]==ps[i])
85 continue;
86 int e=ps[i];
87 swap(ps[rev_ps[i]],ps[i]);
88 v.push_back({ps[i],e});
89 swap(rev_ps[i],rev_ps[e]);
90 }
91 for(int i=0;i<n;i++)
CAPITOLUL 6. IOI 2015 787
92 r[s[i]]=i;
93 for(int i=0;i<t;i++)
94 {
95 swap(s[x[i]],s[y[i]]);
96 swap(r[s[x[i]]],r[s[y[i]]]);
97 if(v.size()>i)
98 {
99 P[i]=r[v[i].first];
100 Q[i]=r[v[i].second];
101 }
102 else
103 {
104 P[i]=0;
105 Q[i]=0;
106 }
107 swap(s[P[i]],s[Q[i]]);
108 swap(r[s[P[i]]],r[s[Q[i]]]);
109 }
110 return t;
111 }
112
113 // -------------- begin grader ------------------
114
115 static char _buffer[1024];
116 static int _currentChar = 0;
117 static int _charsNumber = 0;
118
119 static FILE *_inputFile, *_outputFile;
120
121 static inline int _read()
122 {
123 if (_charsNumber < 0)
124 {
125 exit(1);
126 }
127
128 if (!_charsNumber || _currentChar == _charsNumber)
129 {
130 _charsNumber = (int)fread(_buffer,
131 sizeof(_buffer[0]),
132 sizeof(_buffer),
133 _inputFile);
134 _currentChar = 0;
135 }
136
137 if (_charsNumber <= 0)
138 {
139 return -1;
140 }
141 return _buffer[_currentChar++];
142 }
143
144 static inline int _readInt()
145 {
146 int c, x, s;
147 c = _read();
148 while (c <= 32) c = _read();
149 x = 0;
150 s = 1;
151 if (c == ’-’)
152 {
153 s = -1;
154 c = _read();
155 }
156 while (c > 32)
157 {
158 x *= 10;
159 x += c - ’0’;
160 c = _read();
161 }
162 if (s < 0) x = -x;
163 return x;
164 }
165
166 int main()
167 {
CAPITOLUL 6. IOI 2015 788
36 n = N;
37 for(int i = 0; i < N; i++)
38 {
39 S[i] = qq[i];
40 val[i] = S[i];
41 loc[val[i]] = i;
42 }
43 int l = 0, r = N, m;
44 while(l != r)
45 {
46 int cyc = 0;
47 m = (l + r) >> 1;
48 for(int i = 0; i < m; i++)
49 swap(S[X[i]], S[Y[i]]);
50
51 for(int i = 0; i < n; i++)
52 {
53 if(in[i]) continue;
54 cyc++;
55 dfs(i, S[i]);
56 }
57 if(n - cyc <= m) r = m;
58 else l = m + 1;
59 memset(in, 0, sizeof in);
60 for(int i = 0; i < n; i++)
61 S[i] = val[i];
62
63 }
64
65 for(int i = 0; i < r; i++)
66 swap(S[X[i]], S[Y[i]]);
67 for(int i = 0; i < n; i++)
68 {
69 while(S[i] != i)
70 {
71 sw.push_back({S[i], i});
72 swap(S[i], S[S[i]]);
73 }
74 }
75
76 for(int i = 0; i < r; i++)
77 {
78 swap(val[X[i]], val[Y[i]]);
79 swap(loc[val[X[i]]], loc[val[Y[i]]]);
80 if(sw.empty())
81 {
82 P[i] = 0;
83 Q[i] = 0;
84 }
85 else
86 {
87 P[i] = loc[sw.back().ff];
88 Q[i] = loc[sw.back().ss];
89 swap(val[P[i]], val[Q[i]]);
90 swap(loc[val[P[i]]], loc[val[Q[i]]]);
91 sw.pop_back();
92 }
93 }
94
95 return l;
96 }
97
98 // -------------- begin grader ------------------
99
100 static char _buffer[1024];
101 static int _currentChar = 0;
102 static int _charsNumber = 0;
103
104 static FILE *_inputFile, *_outputFile;
105
106 static inline int _read()
107 {
108 if (_charsNumber < 0)
109 {
110 exit(1);
111 }
CAPITOLUL 6. IOI 2015 790
112
113 if (!_charsNumber || _currentChar == _charsNumber)
114 {
115 _charsNumber = (int)fread(_buffer,
116 sizeof(_buffer[0]),
117 sizeof(_buffer),
118 _inputFile);
119 _currentChar = 0;
120 }
121
122 if (_charsNumber <= 0)
123 {
124 return -1;
125 }
126 return _buffer[_currentChar++];
127 }
128
129 static inline int _readInt()
130 {
131 int c, x, s;
132 c = _read();
133 while (c <= 32) c = _read();
134 x = 0;
135 s = 1;
136 if (c == ’-’)
137 {
138 s = -1;
139 c = _read();
140 }
141 while (c > 32)
142 {
143 x *= 10;
144 x += c - ’0’;
145 c = _read();
146 }
147 if (s < 0) x = -x;
148 return x;
149 }
150
151 int main()
152 {
153 _inputFile = fopen("../tests/subtaskf/25", "rb");
154 _outputFile = fopen("sorting.out", "w");
155
156 int N, M;
157 N = _readInt();
158 int *S = (int*)malloc(sizeof(int) * (unsigned int)N);
159
160 for (int i = 0; i < N; ++i)
161 S[i] = _readInt();
162
163 M = _readInt();
164
165 int *X = (int*)malloc(sizeof(int) * (unsigned int)M),
166 *Y = (int*)malloc(sizeof(int) * (unsigned int)M);
167 for (int i = 0; i < M; ++i)
168 {
169 X[i] = _readInt();
170 Y[i] = _readInt();
171 }
172
173 int *P = (int*)malloc(sizeof(int) * (unsigned int)M),
174 *Q = (int*)malloc(sizeof(int) * (unsigned int)M);
175
176 int ans = findSwapPairs(N, S, M, X, Y, P, Q);
177
178 fprintf(_outputFile, "%d\n", ans);
179
180 for (int i = 0; i < ans; ++i)
181 fprintf(_outputFile, "%d %d\n", P[i], Q[i]);
182
183 return 0;
184 }
185
186 // -------------- end grader ------------------
187 /*
CAPITOLUL 6. IOI 2015 791
71
72 for (int i = 0; i < n; i++)
73 {
74 while (end[i] != i)
75 {
76 swp.push_back({end[i], end[end[i]]});
77 swap(end[i], end[end[i]]);
78 }
79 }
80
81 vector<int> revind(n);
82 for (int i = 0; i < n; i++)
83 {
84 revind[perm[i]] = i;
85 }
86
87 for (int i = 0; i < r; i++)
88 {
89 swap(revind[perm[X[i]]], revind[perm[Y[i]]]);
90 swap(perm[X[i]], perm[Y[i]]);
91 if (i < swp.size())
92 {
93 Q[i] = revind[swp[i].first];
94 P[i] = revind[swp[i].second];
95 swap(revind[swp[i].first], revind[swp[i].second]);
96 swap(perm[Q[i]], perm[P[i]]);
97 }
98 else
99 {
100 Q[i] = 0;
101 P[i] = 0;
102 }
103 }
104
105 return r;
106 }
107
108 // -------------- begin grader ------------------
109
110 static char _buffer[1024];
111 static int _currentChar = 0;
112 static int _charsNumber = 0;
113
114 static FILE *_inputFile, *_outputFile;
115
116 static inline int _read()
117 {
118 if (_charsNumber < 0)
119 {
120 exit(1);
121 }
122
123 if (!_charsNumber || _currentChar == _charsNumber)
124 {
125 _charsNumber = (int)fread(_buffer,
126 sizeof(_buffer[0]),
127 sizeof(_buffer),
128 _inputFile);
129 _currentChar = 0;
130 }
131
132 if (_charsNumber <= 0)
133 {
134 return -1;
135 }
136 return _buffer[_currentChar++];
137 }
138
139 static inline int _readInt()
140 {
141 int c, x, s;
142 c = _read();
143 while (c <= 32) c = _read();
144 x = 0;
145 s = 1;
146 if (c == ’-’)
CAPITOLUL 6. IOI 2015 793
147 {
148 s = -1;
149 c = _read();
150 }
151 while (c > 32)
152 {
153 x *= 10;
154 x += c - ’0’;
155 c = _read();
156 }
157 if (s < 0) x = -x;
158 return x;
159 }
160
161 int main()
162 {
163 _inputFile = fopen("../tests/subtaskf/25", "rb");
164 _outputFile = fopen("sorting.out", "w");
165
166 int N, M;
167 N = _readInt();
168 int *S = (int*)malloc(sizeof(int) * (unsigned int)N);
169
170 for (int i = 0; i < N; ++i)
171 S[i] = _readInt();
172
173 M = _readInt();
174
175 int *X = (int*)malloc(sizeof(int) * (unsigned int)M),
176 *Y = (int*)malloc(sizeof(int) * (unsigned int)M);
177 for (int i = 0; i < M; ++i)
178 {
179 X[i] = _readInt();
180 Y[i] = _readInt();
181 }
182
183 int *P = (int*)malloc(sizeof(int) * (unsigned int)M),
184 *Q = (int*)malloc(sizeof(int) * (unsigned int)M);
185
186 int ans = findSwapPairs(N, S, M, X, Y, P, Q);
187
188 fprintf(_outputFile, "%d\n", ans);
189
190 for (int i = 0; i < ans; ++i)
191 fprintf(_outputFile, "%d %d\n", P[i], Q[i]);
192
193 return 0;
194 }
195
196 // -------------- end grader ------------------
197 /*
198 execution time : 1.828 s
199 */
20 for(i=0;i<z;i++)
21 {
22 swap(a[x[i]],a[y[i]]);
23 }
24 for(i=0;i<n;i++)
25 {
26 c[a[i]]=i;
27 d[b[i]]=i;
28 }
29 j=0;
30 for(i=0;i<z;i++)
31 {
32 swap(d[b[x[i]]],d[b[y[i]]]);
33 swap(b[x[i]],b[y[i]]);
34 while(j<n&&a[j]==j)j++;
35 if(j==n)p[i]=q[i]=0;
36 else
37 {
38 p[i]=d[j],q[i]=d[a[j]];
39 swap(b[d[j]],b[d[a[j]]]);
40 swap(d[j],d[a[j]]);
41 c[a[j]]=c[j];
42 swap(a[j],a[c[j]]);
43 c[j]=j;
44 }
45 }
46
47 for(i=0;i+1<n;i++) if(a[i]>a[i+1]) return false;
48 return true;
49 }
50
51 int findSwapPairs(int N, int S[], int M, int X[], int Y[], int P[], int Q[])
52 {
53 n=N;s=S;m=M;x=X;y=Y;p=P;q=Q;
54 int lo=0,hi=M;
55 while(lo<hi)
56 {
57 int mid=(lo+hi)/2;
58 if(f(mid))hi=mid;
59 else lo=mid+1;
60 }
61 f(lo);
62 return lo;
63 }
64
65 // -------------- begin grader ------------------
66
67 static char _buffer[1024];
68 static int _currentChar = 0;
69 static int _charsNumber = 0;
70
71 static FILE *_inputFile, *_outputFile;
72
73 static inline int _read()
74 {
75 if (_charsNumber < 0)
76 {
77 exit(1);
78 }
79
80 if (!_charsNumber || _currentChar == _charsNumber)
81 {
82 _charsNumber = (int)fread(_buffer,
83 sizeof(_buffer[0]),
84 sizeof(_buffer),
85 _inputFile);
86 _currentChar = 0;
87 }
88
89 if (_charsNumber <= 0)
90 {
91 return -1;
92 }
93 return _buffer[_currentChar++];
94 }
95
CAPITOLUL 6. IOI 2015 795
12
13 #include "sorting.h"
14
15 int findSwapPairs(int N, int S[], int M, int X[], int Y[], int P[], int Q[])
16 {
17 auto check = [&](int R)
18 {
19 vector<int> s(N), ws(N), wf(N);
20 REP(i, N) s[i] = S[i];
21 auto f = s;
22 REP(i, R) swap(f[X[i]], f[Y[i]]);
23 REP(i, N)
24 {
25 ws[S[i]] = i;
26 wf[f[i]] = i;
27 }
28
29 int j = 0;
30 REP(i, R)
31 {
32 int &p = s[X[i]], &q = s[Y[i]];
33 swap(p, q);
34 swap(ws[p], ws[q]);
35
36 while(j < N && j == f[j]) j++;
37 if(j < N)
38 {
39 int &a = ws[j], &b = ws[f[j]], &x = wf[j], &y = wf[f[j]];
40 P[i] = a, Q[i] = b;
41 swap(a, b), swap(s[a], s[b]);
42 swap(x, y), swap(f[x], f[y]);
43 }
44 else P[i] = Q[i] = 0;
45 }
46
47 REP(i, N) if(i != s[i]) return false;
48 return true;
49 };
50
51 int l = 0, r = M;
52 while(l < r)
53 {
54 int m = (l + r) / 2;
55 if(check(m))
56 r = m;
57 else
58 l = m + 1;
59 }
60
61 check(l);
62 return l;
63 }
64
65 // -------------- begin grader ------------------
66
67 static char _buffer[1024];
68 static int _currentChar = 0;
69 static int _charsNumber = 0;
70
71 static FILE *_inputFile, *_outputFile;
72
73 static inline int _read()
74 {
75 if (_charsNumber < 0)
76 {
77 exit(1);
78 }
79
80 if (!_charsNumber || _currentChar == _charsNumber)
81 {
82 _charsNumber = (int)fread(_buffer,
83 sizeof(_buffer[0]),
84 sizeof(_buffer),
85 _inputFile);
86 _currentChar = 0;
87 }
CAPITOLUL 6. IOI 2015 797
88
89 if (_charsNumber <= 0)
90 {
91 return -1;
92 }
93 return _buffer[_currentChar++];
94 }
95
96 static inline int _readInt()
97 {
98 int c, x, s;
99 c = _read();
100 while (c <= 32) c = _read();
101 x = 0;
102 s = 1;
103 if (c == ’-’)
104 {
105 s = -1;
106 c = _read();
107 }
108 while (c > 32)
109 {
110 x *= 10;
111 x += c - ’0’;
112 c = _read();
113 }
114 if (s < 0) x = -x;
115 return x;
116 }
117
118 int main()
119 {
120 _inputFile = fopen("../tests/subtaskf/25", "rb");
121 _outputFile = fopen("sorting.out", "w");
122
123 int N, M;
124 N = _readInt();
125 int *S = (int*)malloc(sizeof(int) * (unsigned int)N);
126
127 for (int i = 0; i < N; ++i)
128 S[i] = _readInt();
129
130 M = _readInt();
131
132 int *X = (int*)malloc(sizeof(int) * (unsigned int)M),
133 *Y = (int*)malloc(sizeof(int) * (unsigned int)M);
134 for (int i = 0; i < M; ++i)
135 {
136 X[i] = _readInt();
137 Y[i] = _readInt();
138 }
139
140 int *P = (int*)malloc(sizeof(int) * (unsigned int)M),
141 *Q = (int*)malloc(sizeof(int) * (unsigned int)M);
142
143 int ans = findSwapPairs(N, S, M, X, Y, P, Q);
144
145 fprintf(_outputFile, "%d\n", ans);
146
147 for (int i = 0; i < ans; ++i)
148 fprintf(_outputFile, "%d %d\n", P[i], Q[i]);
149
150 return 0;
151 }
152
153 // -------------- end grader ------------------
154 /*
155 execution time : 3.016 s
156 */
4 #include <string.h>
5
6 #include "sorting.h"
7
8 #include <bits/stdc++.h>
9
10 using namespace std;
11
12 mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
13
14 typedef long long ll;
15 typedef long double ld;
16
17 #define INF 2001001001
18 #define MOD 1000000007
19
20 int N,S[200001];
21 int M,X[600001],Y[600001];
22 int arr[200001];
23 bool vis[200001];
24 int to[200001];
25
26 deque<pair<int,int>>q;
27
28 int pos[200001];
29
30 void dfs(int node)
31 {
32 vis[node]=true;
33 if (!vis[arr[node]]){
34 q.push_back({node,arr[node]});
35 dfs(arr[node]);
36 }
37 }
38
39 bool check(int mid)
40 {
41 q.clear();
42 for (int i=0;i<N;i++)
43 {
44 arr[i]=S[i];
45 vis[i]=false;
46 }
47 for (int i=1;i<=mid;i++)
48 swap(arr[X[i]],arr[Y[i]]);
49 int comps=0;
50 for (int i=0;i<N;i++)
51 {
52 pos[arr[i]]=i;
53 if (!vis[arr[i]])
54 {
55 comps++;
56 q.push_back({i,arr[i]});
57 dfs(arr[i]);
58 q.pop_back();
59 }
60 }
61 return N-comps<=mid;
62 }
63
64 int findSwapPairs(int n,int s[],int m, int x[], int y[], int P[], int Q[])
65 {
66 N=n;
67 for (int i=0;i<N;i++)
68 S[i]=s[i];
69 M=m;
70 for (int i=1;i<=M;i++)
71 {
72 X[i]=x[i-1];
73 Y[i]=y[i-1];
74 }
75 int low=-1,high=M+1;
76 while (low+1<high)
77 {
78 int mid=(low+high)/2;
79 if (check(mid))
CAPITOLUL 6. IOI 2015 799
80 high=mid;
81 else
82 low=mid;
83 }
84
85 check(high);
86 for (int i=high;i>=1;i--)
87 {
88 if (!q.empty()){
89 P[i-1]=pos[q[0].first];
90 Q[i-1]=pos[q[0].second];
91 swap(pos[arr[X[i]]],pos[arr[Y[i]]]);
92 swap(arr[X[i]],arr[Y[i]]);
93 q.pop_front();
94 }
95 }
96
97 for (int i=1;i<=high;i++)
98 {
99 swap(S[X[i]],S[Y[i]]);
100 swap(S[P[i-1]],S[Q[i-1]]);
101 }
102 for (int i=0;i<N;i++)
103 if (S[i]!=i)
104 assert(0);
105 return high;
106 }
107
108 // -------------- begin grader ------------------
109
110 static char _buffer[1024];
111 static int _currentChar = 0;
112 static int _charsNumber = 0;
113
114 static FILE *_inputFile, *_outputFile;
115
116 static inline int _read()
117 {
118 if (_charsNumber < 0)
119 {
120 exit(1);
121 }
122
123 if (!_charsNumber || _currentChar == _charsNumber)
124 {
125 _charsNumber = (int)fread(_buffer,
126 sizeof(_buffer[0]),
127 sizeof(_buffer),
128 _inputFile);
129 _currentChar = 0;
130 }
131
132 if (_charsNumber <= 0)
133 {
134 return -1;
135 }
136 return _buffer[_currentChar++];
137 }
138
139 static inline int _readInt()
140 {
141 int c, x, s;
142 c = _read();
143 while (c <= 32) c = _read();
144 x = 0;
145 s = 1;
146 if (c == ’-’)
147 {
148 s = -1;
149 c = _read();
150 }
151 while (c > 32)
152 {
153 x *= 10;
154 x += c - ’0’;
155 c = _read();
CAPITOLUL 6. IOI 2015 800
156 }
157 if (s < 0) x = -x;
158 return x;
159 }
160
161 int main()
162 {
163 _inputFile = fopen("../tests/subtaskf/25", "rb");
164 _outputFile = fopen("sorting.out", "w");
165
166 int N, M;
167 N = _readInt();
168 int *S = (int*)malloc(sizeof(int) * (unsigned int)N);
169
170 for (int i = 0; i < N; ++i)
171 S[i] = _readInt();
172
173 M = _readInt();
174
175 int *X = (int*)malloc(sizeof(int) * (unsigned int)M),
176 *Y = (int*)malloc(sizeof(int) * (unsigned int)M);
177 for (int i = 0; i < M; ++i)
178 {
179 X[i] = _readInt();
180 Y[i] = _readInt();
181 }
182
183 int *P = (int*)malloc(sizeof(int) * (unsigned int)M),
184 *Q = (int*)malloc(sizeof(int) * (unsigned int)M);
185
186 int ans = findSwapPairs(N, S, M, X, Y, P, Q);
187
188 fprintf(_outputFile, "%d\n", ans);
189
190 for (int i = 0; i < ans; ++i)
191 fprintf(_outputFile, "%d %d\n", P[i], Q[i]);
192
193 return 0;
194 }
195
196 // -------------- end grader ------------------
197 /*
198 execution time : 2.341 s
199 */
6.6 Towns
Problema 6 - Towns 100 de puncte
Author: Bang Ye Wu (TWN)
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 ecare 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 ecare 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.
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 ecare test:
CAPITOLUL 6. IOI 2015 802
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 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 ³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 ecare test grader-ul a³eaz valoarea returnat de hubDistance ³i num rul de ape-
luri 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 specicarea listei de autostr zi. De notat c este permis s modici
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 6. IOI 2015 803
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 nd 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, nd 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 nd 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 dierent values in B identies 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 i
Then, we can solve the giant component problem by algorithms for the following problem:
There aren 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 sucient 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 6. IOI 2015 804
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
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include "graderlib.c"
8
9 #include <bits/stdc++.h>
10
11 using namespace std;
12
13 const int maxn = 150;
14 const int inf = 0x3f3f3f3f;
15
16 int qs[maxn][maxn];
17 int deb = 0;
18
19 int n;
20 int query(int a, int b)
21 {
22 assert(a < n && b < n && a >= 0 && b >= 0);
23 if (a > b) swap(a, b);
24 if (qs[a][b] == -1) qs[a][b] = getDistance(a, b);
25 return qs[a][b];
26 }
27
28 int a, b;
29 int B;
30 bool subtree(int x, int y)
31 {
32 int xd = (query(a, x) + query(b, x) - query(a, b)) / 2;
33 int yd = (query(a, y) + query(b, y) - query(a, b)) / 2;
34 return (xd + yd) > query(x, y);
35 }
36
37 int hubDistance(int n, int sub)
38 {
39 deb++;
40 ::n = n;
41 memset(qs, -1, sizeof qs);
42 a = b = B = 0;
43
44 for (int i = 0; i < n; i++)
45 qs[i][i] = 0;
46
47 a = 0, b = 0;
48 for (int i = 0; i < n; i++)
49 if (query(0, a) < query(0, i)) a = i;
50
51 for (int i = 0; i < n; i++)
52 if (query(a, b) < query(a, i)) b = i;
53
54 B = b; b = 0;
55 int hu = -1, out = inf;
56 for (int i = 0; i < n; i++)
57 {
58 int cd = (query(a, i) + query(b, i) - query(a, b)) / 2;
59 int ad = query(a, i) - cd;
60 int bd = query(a, B) - ad;
61
62 if (out > max(ad, bd)) out = max(ad, bd), hu = ad;
63 }
64 assert(hu > -1);
65
66 int lef = 0, rig = 0;
67 vector<int> v;
68 for (int i = 0; i < n; i++)
69 {
70 int cd = (query(a, i) + query(b, i) - query(a, b)) / 2;
71 int ad = query(a, i) - cd;
72
73 if (ad < hu) lef++;
74 else
75 if (ad > hu) rig++;
76 else v.push_back(i);
77 }
78
79 if (max(lef, rig) > n / 2)
80 {
CAPITOLUL 6. IOI 2015 806
81 hu = query(a, B) - hu;
82
83 int lef = 0, rig = 0;
84 vector<int> v;
85 for (int i = 0; i < n; i++)
86 {
87 int cd = (query(a, i) + query(b, i) - query(a, b)) / 2;
88 int ad = query(a, i) - cd;
89
90 if (ad < hu) lef++;
91 else
92 if (ad > hu) rig++;
93 else v.push_back(i);
94 }
95
96 if (max(lef, rig) > n / 2) return -out;
97 }
98
99 if (v.size() == 0)
100 {
101 if (max(lef, rig) > n / 2) return -out;
102 else return out;
103 }
104
105 vector<int> li, buk;
106 li.push_back(v[0]);
107 for (int i = 1; i < v.size(); i++)
108 {
109 if (subtree(v[i], li.back())) buk.push_back(v[i]);
110 else
111 {
112 li.push_back(v[i]);
113 if (!buk.empty())
114 {
115 li.push_back(buk.back());
116 buk.pop_back();
117 }
118 }
119 }
120
121 int cnt = 0;
122 int kan = li.back();
123
124 while (li.size() > 0)
125 {
126 if (subtree(li.back(), kan))
127 {
128 if (li.size() == 1)
129 {
130 buk.push_back(li.back());
131 li.pop_back();
132 }
133 else
134 {
135 li.pop_back();
136 li.pop_back();
137 cnt++;
138 }
139 }
140 else
141 {
142 if (buk.empty()) return out;
143 else
144 {
145 li.pop_back();
146 buk.pop_back();
147 cnt++;
148 }
149 }
150 }
151
152 cnt += buk.size();
153
154 if (cnt > n / 2) return -out;
155 else return out;
156 }
CAPITOLUL 6. IOI 2015 807
157
158 // ------------- begin grader ----------------------
159
160 int main()
161 {
162 FILE *f;
163 f = freopen("../tests/subtask_6/03","r",stdin);
164 assert(f != NULL);
165
166 f = freopen("towns.out","w",stdout);
167 assert(f != NULL);
168
169 int ncase, R, N;
170 int subtask;
171 int ret;
172
173 ret = scanf("%d%d",&subtask,&ncase);
174 assert(ret == 2);
175
176 for (int i = 0; i < ncase; i++)
177 {
178 ret = scanf("%d",&N);
179 assert(ret == 1);
180
181 _ini_query(N,subtask);
182 R=hubDistance(N,subtask);
183
184 printf("%d\n",R);
185 }
186
187 return 0;
188 }
189
190 // ------------- end grader ------------------------
191 /*
192 execution time : 0.328 s
193 */
36 }
37
38 int chk = -1, l = 0;
39
40 for(auto& x : cntr)
41 {
42 if(l <= N / 2 && N - (l += x.ss) <= N / 2)
43 {
44 if(max(x.ff, D - x.ff) == r)
45 {
46 if(x.ss <= N / 2) return r;
47 chk = x.ff << 1;
48 }
49 }
50 }
51
52 if(chk == -1) return -r;
53 vector<vector<int> > s, t, de;
54 vector<int> la;
55 for(int i = 0; i < N; i++)
56 if(chk == T + d[1][i] - d[0][i])
57 s.push_back({i});
58
59 while(s.size() > 1)
60 {
61 for(int i = 1; i < s.size(); i += 2)
62 {
63 if(getDistance(s[i - 1][0],
64 s[i][0]) == d[0][s[i - 1][0]] + d[1][s[i][0]] - T)
65 {
66 de.push_back(s[i - 1]);
67 de.push_back(s[i]);
68 }
69 else
70 {
71 for(int& x : s[i - 1])
72 s[i].push_back(x);
73 t.push_back(s[i]);
74 }
75 }
76
77 if(s.size() & 1)
78 {
79 de.push_back(s.back());
80 la = s.back();
81 }
82 swap(s, t);
83 t.clear();
84 }
85
86 int sz = 0;
87 if(s.empty()) s.push_back(la);
88 else sz = s[0].size();
89
90 if(s[0].empty()) return r;
91 for(auto& x : de)
92 {
93 if(getDistance(x[0], s[0][0]) != d[0][s[0][0]] + d[1][x[0]] - T)
94 sz += x.size();
95 }
96
97 if(sz > N / 2) return -r;
98 return r;
99 }
100
101 // ------------- begin grader ----------------------
102
103 int main()
104 {
105 FILE *f;
106 f = freopen("../tests/subtask_6/03","r",stdin);
107 assert(f != NULL);
108
109 f = freopen("towns.out","w",stdout);
110 assert(f != NULL);
111
CAPITOLUL 6. IOI 2015 809
48 else
49 {
50 domin[act].push_back(it);
51 bal--;
52 }
53 }
54 sz[act]++;
55 }
56 int ap=0;
57 for(auto it:cand)
58 {
59 if(sz[it])
60 {
61 if(eq(act,it)) ap+=sz[it]-(int)domin[it].size();
62 else
63 {
64 for(auto oth: domin[it])
65 {
66 ap+=eq(act,oth);
67 }
68 }
69 }
70 }
71 return (ap<=n/2);
72 }
73
74 int hubDistance(int N, int sub)
75 {
76 int d1=0,R=0,mx=0,d2=0;
77 n=N;
78 for(int i=0;i<2;i++)
79 for(int j=0;j<n;j++)
80 d[i][j]=0;
81 for(int i=1; i<n; i++)
82 {
83 d[0][i]=getDistance(0,i);
84 if(d[0][i]>d[0][d1])
85 d1=i;
86 }
87
88 for(int i=0; i<n; i++)
89 if(i!=d1)
90 {
91 d[1][i]=getDistance(d1,i);
92 if(d[1][i]>mx)
93 mx=d[1][i],d2=i;
94 }
95
96 int minDist=(1<<30);
97 int lim=d[1][d2]-(d[0][d2]+d[1][d2]-d[0][d1])/2;
98 for(int i=0; i<n; i++)
99 {
100 to[i]=(d[0][i]+d[1][i]-d[0][d1])/2;
101 wh[i]=(d[1][i]-to[i]);
102 if(max(wh[i],mx-wh[i])<minDist&&wh[i]<=lim)
103 minDist=max(wh[i],mx-wh[i]);
104 }
105
106 vector<int> hubs;
107 for(int i=0;i<n;i++)
108 if(max(wh[i],mx-wh[i])==minDist&&wh[i]<=lim)
109 hubs.push_back(wh[i]);
110
111 sort(hubs.begin(),hubs.end());
112
113 hubs.resize(unique(hubs.begin(),hubs.end())-hubs.begin());
114
115 bool ok=0;
116 for(auto cen :hubs)
117 {
118 int mici=0,mari=0;
119 for(int i=0;i<n;i++)
120 {
121 if(wh[i]<cen) mici++;
122 if(wh[i]>cen) mari++;
123 }
CAPITOLUL 6. IOI 2015 811
124 if(mici<=n/2&&mari<=n/2)
125 ok=checkHub(cen);
126 }
127
128 R=minDist;
129 if(!ok) R=-R;
130 return R;
131 }
132
133 // ------------- begin grader ----------------------
134
135 int main()
136 {
137 FILE *f;
138 f = freopen("../tests/subtask_6/03","r",stdin);
139 assert(f != NULL);
140
141 f = freopen("towns.out","w",stdout);
142 assert(f != NULL);
143
144 int ncase, R, N;
145 int subtask;
146 int ret;
147
148 ret = scanf("%d%d",&subtask,&ncase);
149 assert(ret == 2);
150
151 for (int i = 0; i < ncase; i++)
152 {
153 ret = scanf("%d",&N);
154 assert(ret == 1);
155
156 _ini_query(N,subtask);
157 R=hubDistance(N,subtask);
158
159 printf("%d\n",R);
160 }
161
162 return 0;
163 }
164
165 // ------------- end grader ------------------------
166 /*
167 execution time : 0.344 s
168 */
28 }
IOI 201432
7.1 Game
Problema 1 - Game 100 de puncte
Authors: Jonathan Moshei and Nir Lavee, Israel
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 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 (e direct, e 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 ecare 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 arma 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 e 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
32
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).
813
CAPITOLUL 7. IOI 2014 814
Î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 nal 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 r spuns no la ultima întrebare
acest lucru nu ar 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
e 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 ³ier, numit game.c, game.cpp sau game.pas. în acest ³ier vor
implementate cele dou funcµii descrise mai sus, utilizând urm toarele antete.
pentru programele C/C++
void initialize(int n);
int hasEdge(int u, int v);
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.
An O n4 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-rst search to nd 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. If the contestant answers yes, let w be the representative after uniting D u and D v .
For each x that is a representative of some connected component, both S w, x and S x, w
are updated to S R u, x S R v , x.
CAPITOLUL 7. IOI 2014 816
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.
24 return (ctr[v]==v);
25 }
26
27 // -------------- begin grader ---------------
28
29 int read_int()
30 {
31 int x;
32 assert(scanf("%d", &x) == 1);
33 return x;
34 }
35
36 int main()
37 {
38 auto t1 = clock();
39
40 std::freopen("../tests/03-114.in", "r", stdin) ;
41 std::freopen("game.out", "w", stdout) ;
42
43 int n, u, v;
44 n = read_int();
45
46 auto t2 = clock();
47
48 initialize(n);
49 for (int i = 0; i < n * (n - 1) / 2; i++)
50 {
51 u = read_int();
52 v = read_int();
53 printf("%d\n", hasEdge(u, v));
54 }
55
56 auto t3 = clock();
57
58 fclose(stdout);
59
60 auto t4 = clock();
61
62 // reset console output
63 freopen("CON", "w", stdout);
64
65 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
66 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
67 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
68
69 return 0;
70 }
71
72 // -------------- end grader ---------------
73 /*
74 t2-t1 = 0
75 t3-t2 = 4.312
76 t4-t3 = 0.016
77
78 Process returned 0 (0x0) execution time : 4.359 s
79 Press any key to continue.
80 argc = 4
81 checker
82 ../tests/03-114.in
83 game.out
84 ../tests/03-114.out
85 ----------------------
86 1
87 Correct
88
89 Process returned 0 (0x0) execution time : 2.375 s
90 Press any key to continue.
91 */
5
6 using namespace std;
7
8 int cnt[1500];
9 int first_time;
10
11 void initialize(int n) {}
12 int c[1500];
13 int hasEdge(int u, int v) {
14 return ++c[u > v ? u : v] == (u > v ? u : v);
15 }
16
17 // -------------- begin grader ---------------
18
19 int read_int()
20 {
21 int x;
22 assert(scanf("%d", &x) == 1);
23 return x;
24 }
25
26 int main()
27 {
28 auto t1 = clock();
29
30 std::freopen("../tests/03-114.in", "r", stdin) ;
31 std::freopen("game.out", "w", stdout) ;
32
33 int n, u, v;
34 n = read_int();
35
36 auto t2 = clock();
37
38 initialize(n);
39 for (int i = 0; i < n * (n - 1) / 2; i++)
40 {
41 u = read_int();
42 v = read_int();
43 printf("%d\n", hasEdge(u, v));
44 }
45
46 auto t3 = clock();
47
48 fclose(stdout);
49
50 auto t4 = clock();
51
52 // reset console output
53 freopen("CON", "w", stdout);
54
55 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
56 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
57 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
58
59 return 0;
60 }
61
62 // -------------- end grader ---------------
63 /*
64 t2-t1 = 0
65 t3-t2 = 3.765
66 t4-t3 = 0.016
67
68 Process returned 0 (0x0) execution time : 3.828 s
69 Press any key to continue.
70 argc = 4
71 checker
72 ../tests/03-114.in
73 game.out
74 ../tests/03-114.out
75 ----------------------
76 1
77 Correct
78
79 Process returned 0 (0x0) execution time : 2.358 s
80 Press any key to continue.
CAPITOLUL 7. IOI 2014 819
81 */
72 argc = 4
73 checker
74 ../tests/03-114.in
75 game.out
76 ../tests/03-114.out
77 ----------------------
78 1
79 Correct
80
81 Process returned 0 (0x0) execution time : 2.328 s
82 Press any key to continue.
83 */
61 return 0;
62 }
63
64 // -------------- end grader ---------------
65 /*
66 t2-t1 = 0
67 t3-t2 = 3.791
68 t4-t3 = 0.015
69
70 Process returned 0 (0x0) execution time : 3.838 s
71 Press any key to continue.
72 argc = 4
73 checker
74 ../tests/03-114.in
75 game.out
76 ../tests/03-114.out
77 ----------------------
78 1
79 Correct
80
81 Process returned 0 (0x0) execution time : 2.344 s
82 Press any key to continue.
83 */
7.2 Rail
Problema 2 - Rail 100 de puncte
Author: Vytautas Gruslys, Lithuania
Î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 gura
CAPITOLUL 7. IOI 2014 822
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 gura 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 nal ajungând în gara 2 aat în
blocul 3.
Deoarece pot exista mai multe rute posibile, distanµa de la o gar la alta se dene³te ca ind
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 a g rile ³i în ce tip de bloc se a acestea. Singurul indiciu
r mas în sistem este num rul blocului în care se a gara 0, care se a 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 ecare gar num rul
³i tipul blocului în care se a .
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 nalul execuµiei acestei funcµii
num rul blocului în care se a gara i trebuie s se ae în celula location[i].
stype: un tablou unidimensional de dimensiune n; la nalul execuµiei acestei funcµii tipul
blocului în care se a gara i trebuie s se ae î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 blo-
curilor în care se a 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 a î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 a în blocuri de tip D, ³i
toate g rile situate la vestul g rii
0 se a î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 7. IOI 2014 823
Detalii de implementare
Voi trebuie s înc rcaµi exact un ³ier, denumit rail.c, rail.cpp sau rail.pas. Acest ³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 rst 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 7. IOI 2014 824
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 nd the answer.
173 }
174 else
175 if(stations[x].type==2 && stations[y].type==1)
176 {
177 ret = stations[x].location-
178 stations[stations[x].L].location+
179 stations[stations[y].R].location-
180 stations[stations[x].L].location+
181 stations[stations[y].R].location-
182 stations[y].location;
183 }
184
185 return ret;
186 }
187
188 void getInput()
189 {
190 int g;
191 g = scanf("%d",&SUBTASK);
192 g = scanf("%d",&S);
193
194 int s;
195 for (s = 0; s < S; s++)
196 {
197 int type, location;
198 g = scanf(" %d %d",&type,&location);
199 stations[s].index = s;
200 stations[s].location = location;
201 stations[s].type = type;
202 stations[s].L = -1;
203 stations[s].R = -1;
204 }
205
206 qsort(stations, S, sizeof(STATION), cmp_fun_1);
207 now_I_want_to_getLR();
208 qsort(stations, S, sizeof(STATION), cmp_fun_2);
209 }
210
211 int serverGetStationNumber()
212 {
213 return S;
214 }
215
216 int serverGetSubtaskNumber()
217 {
218 return SUBTASK;
219 }
220
221 int serverGetFirstStationLocation()
222 {
223 return stations[0].location;
224 }
225
226 int main()
227 {
228 auto t1 = clock();
229
230 std::freopen("../tests/04-020.in", "r", stdin) ;
231 //std::freopen("rail.out", "w", stdout) ;
232
233 int i;
234 getInput();
235 cnt = 0;
236
237 int location[10005];
238 int type[10005];
239 int ok = 1;
240
241 auto t2 = clock();
242
243 findLocation(S, serverGetFirstStationLocation(),location, type);
244
245 auto t3 = clock();
246
247 if(SUBTASK==3 && cnt>S*(S-1)) ok = 0;
248 if(SUBTASK==4 && cnt>3*(S-1)) ok = 0;
CAPITOLUL 7. IOI 2014 828
249
250 for (i = 0; i < S; i++)
251 if(type[i]!=stations[i].type || location[i]!=stations[i].location)
252 ok = 0;
253
254 if(ok==0) printf("Incorrect\n\n");
255 else printf("Correct\n\n");
256
257 fclose(stdout);
258
259 auto t4 = clock();
260
261 // reset console output
262 freopen("CON", "w", stdout);
263
264 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
265 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
266 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
267
268 return 0;
269 }
270 // -------------- end grader ----------------------
271 /*
272 Correct
273
274 t2-t1 = 0.031
275 t3-t2 = 0.015
276 t4-t3 = 0.016
277
278 Process returned 0 (0x0) execution time : 0.094 s
279 Press any key to continue.
280 */
41 #include "rail.h"
42
43 void findLocation(int n, int x, int p[], int t[])
44 {
45 if(n==1)
46 {
47 p[0]=x; t[0]=1;
48 return;
49 }
50 int a[n+5],b[n+5];
51 for(int i=1;i<n;i++) a[i]=getDistance(0,i);
52 int mn=INF,y=-1;
53 for(int i=1;i<n;i++)
54 {
55 if(a[i]<mn) mn=a[i],y=i;
56 }
57 for(int i=0;i<n;i++)
58 {
59 if(i==y) continue;
60 b[i]=getDistance(y,i);
61 }
62 mn=INF;
63 int z=-1;
64 for(int i=0;i<n;i++)
65 {
66 if(i==y) continue;
67 if(b[i]<mn) mn=b[i],z=i;
68 }
69 int diff=b[z]-a[y];
70 p[z]=x-diff;
71 p[y]=p[z]+b[z];
72 t[z]=1;
73 t[y]=2;
74 for(int i=0;i<n;i++)
75 {
76 a[i]+=diff;
77 }
78 vector <pi> l,r;
79 vector <int> u,v;
80 for(int i=0;i<n;i++)
81 {
82 if(i==y || i==z) continue;
83 if(i==0) a[i]=2*(p[y]-p[z])-diff;
84 if(a[i]>b[i]) l.pb({b[i],i});
85 else r.pb({a[i],i});
86 }
87
88 sort(l.begin(),l.end());
89 u.pb(p[z]);
90 int f=z;
91 for(pi i : l)
92 {
93 int d=getDistance(i.y,f);
94 p[i.y]=p[f]+d;
95 if(p[i.y]>=p[z])
96 {
97 p[i.y]=p[y]-b[i.y];
98 t[i.y]=1;
99 u.pb(p[i.y]);
100 f=i.y;
101 }
102 int c=*(lower_bound(u.begin(),u.end(),p[i.y],greater<int>()));
103 if(b[i.y]==p[i.y]+p[y]-2*c && p[i.y]!=c)
104 {
105 t[i.y]=2;
106 }
107 else
108 {
109 p[i.y]=p[y]-b[i.y];
110 t[i.y]=1;
111 u.pb(p[i.y]);
112 f=i.y;
113 }
114 }
115
116 sort(r.begin(),r.end());
CAPITOLUL 7. IOI 2014 830
117 v.pb(p[y]);
118 f=y;
119 for(pi i : r)
120 {
121 int d=getDistance(i.y,f);
122 p[i.y]=p[f]-d;
123 if(p[i.y]<=p[y])
124 {
125 p[i.y]=p[z]+a[i.y];
126 t[i.y]=2;
127 v.pb(p[i.y]);
128 f=i.y;
129 }
130 int c=*(lower_bound(v.begin(),v.end(),p[i.y]));
131 if(a[i.y]==2*c-p[i.y]-p[z] && p[i.y]!=c)
132 {
133 t[i.y]=1;
134 }
135 else
136 {
137 p[i.y]=p[z]+a[i.y];
138 t[i.y]=2;
139 v.pb(p[i.y]);
140 f=i.y;
141 }
142 }
143 }
144
145 // ------------- begin grader ---------------------
146
147 typedef struct Station
148 {
149 int index;
150 int type;
151 int location;
152 int L,R;
153 } STATION;
154
155 long long cnt;
156 static int S,SUBTASK;
157 static STATION stations[10004];
158
159 int cmp_fun_1(const void *a,const void *b)
160 {
161 STATION c,d;
162 c = *(STATION*)(a);
163 d = *(STATION*)(b);
164 return c.location < d.location ? -1 : 1;
165 }
166
167 int cmp_fun_2(const void *a,const void *b)
168 {
169 STATION c,d;
170 c = *(STATION*)(a);
171 d = *(STATION*)(b);
172 return c.index < d.index ? -1 : 1;
173 }
174
175 void now_I_want_to_getLR()
176 {
177 int now = stations[S-1].index,i;
178 for(i=S-2;i>=0;i--)
179 {
180 stations[i].R = now;
181 if(stations[i].type==2) now = stations[i].index;
182 }
183 now = stations[0].index;
184 for(i=1;i<S;i++)
185 {
186 stations[i].L = now;
187 if(stations[i].type==1) now = stations[i].index;
188 }
189 }
190
191 int getDistance(int x,int y)
192 {
CAPITOLUL 7. IOI 2014 831
193 cnt++;
194 if(x==y) return 0;
195 if(x<0 || x>=S || y<0 || y>=S) return -1;
196 if(stations[x].location > stations[y].location)
197 {
198 int tmp = x;
199 x = y;
200 y = tmp;
201 }
202
203 int ret = 0;
204 if(stations[x].type==1 && stations[y].type==1)
205 {
206 ret = stations[stations[y].R].location-
207 stations[x].location+
208 stations[stations[y].R].location-
209 stations[y].location;
210 }
211 else
212 if(stations[x].type==1 && stations[y].type==2)
213 {
214 ret = stations[y].location-stations[x].location;
215 }
216 else
217 if(stations[x].type==2 && stations[y].type==2)
218 {
219 ret = stations[x].location-
220 stations[stations[x].L].location+
221 stations[y].location-
222 stations[stations[x].L].location;
223 }
224 else
225 if(stations[x].type==2 && stations[y].type==1)
226 {
227 ret = stations[x].location-
228 stations[stations[x].L].location+
229 stations[stations[y].R].location-
230 stations[stations[x].L].location+
231 stations[stations[y].R].location-
232 stations[y].location;
233 }
234
235 return ret;
236 }
237
238 void getInput()
239 {
240 int g;
241 g = scanf("%d",&SUBTASK);
242 g = scanf("%d",&S);
243
244 int s;
245 for (s = 0; s < S; s++)
246 {
247 int type, location;
248 g = scanf(" %d %d",&type,&location);
249 stations[s].index = s;
250 stations[s].location = location;
251 stations[s].type = type;
252 stations[s].L = -1;
253 stations[s].R = -1;
254 }
255
256 qsort(stations, S, sizeof(STATION), cmp_fun_1);
257 now_I_want_to_getLR();
258 qsort(stations, S, sizeof(STATION), cmp_fun_2);
259 }
260
261 int serverGetStationNumber()
262 {
263 return S;
264 }
265
266 int serverGetSubtaskNumber()
267 {
268 return SUBTASK;
CAPITOLUL 7. IOI 2014 832
269 }
270
271 int serverGetFirstStationLocation()
272 {
273 return stations[0].location;
274 }
275
276 int main()
277 {
278 auto t1 = clock();
279
280 std::freopen("../tests/04-020.in", "r", stdin) ;
281 //std::freopen("rail.out", "w", stdout) ;
282
283 int i;
284 getInput();
285 cnt = 0;
286
287 int location[10005];
288 int type[10005];
289 int ok = 1;
290
291 auto t2 = clock();
292
293 findLocation(S, serverGetFirstStationLocation(),location, type);
294
295 auto t3 = clock();
296
297 if(SUBTASK==3 && cnt>S*(S-1)) ok = 0;
298 if(SUBTASK==4 && cnt>3*(S-1)) ok = 0;
299
300 for (i = 0; i < S; i++)
301 if(type[i]!=stations[i].type || location[i]!=stations[i].location)
302 ok = 0;
303
304 if(ok==0) printf("Incorrect\n\n");
305 else printf("Correct\n\n");
306
307 fclose(stdout);
308
309 auto t4 = clock();
310
311 // reset console output
312 freopen("CON", "w", stdout);
313
314 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
315 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
316 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
317
318 return 0;
319 }
320 // -------------- end grader ----------------------
321 /*
322 Correct
323
324 t2-t1 = 0.031
325 t3-t2 = 0.015
326 t4-t3 = 0
327
328 Process returned 0 (0x0) execution time : 0.078 s
329 Press any key to continue.
330 */
163 now_I_want_to_getLR();
164 qsort(stations, S, sizeof(STATION), cmp_fun_2);
165 }
166
167 int serverGetStationNumber()
168 {
169 return S;
170 }
171
172 int serverGetSubtaskNumber()
173 {
174 return SUBTASK;
175 }
176
177 int serverGetFirstStationLocation()
178 {
179 return stations[0].location;
180 }
181
182 int main()
183 {
184 auto t1 = clock();
185
186 std::freopen("../tests/04-020.in", "r", stdin) ;
187 //std::freopen("rail.out", "w", stdout) ;
188
189 int i;
190 getInput();
191 cnt = 0;
192
193 int location[10005];
194 int type[10005];
195 int ok = 1;
196
197 auto t2 = clock();
198
199 findLocation(S, serverGetFirstStationLocation(),location, type);
200
201 auto t3 = clock();
202
203 if(SUBTASK==3 && cnt>S*(S-1)) ok = 0;
204 if(SUBTASK==4 && cnt>3*(S-1)) ok = 0;
205
206 for (i = 0; i < S; i++)
207 if(type[i]!=stations[i].type || location[i]!=stations[i].location)
208 ok = 0;
209
210 if(ok==0) printf("Incorrect\n\n");
211 else printf("Correct\n\n");
212
213 fclose(stdout);
214
215 auto t4 = clock();
216
217 // reset console output
218 freopen("CON", "w", stdout);
219
220 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
221 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
222 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
223
224 return 0;
225 }
226 // -------------- end grader ----------------------
227 /*
228 Correct
229
230 t2-t1 = 0.031
231 t3-t2 = 0.031
232 t4-t3 = 0
233
234 Process returned 0 (0x0) execution time : 0.109 s
235 Press any key to continue.
236 */
1 // https://oj.uz/submission/139096 87 ms 888 KB
2
3 #include "rail.h"
4 #include <bits/stdc++.h>
5
6 using namespace std;
7
8 void findLocation(int n, int first, int l[], int t[])
9 {
10 l[0] = first;
11 t[0] = 1;
12 vector <pair <int, int>> v;
13 for (int i = 1; i < n; i++)
14 {
15 v.push_back({getDistance(0, i), i});
16 }
17
18 sort(v.begin(), v.end());
19 l[v[0].second] = first + v[0].first;
20 t[v[0].second] = 2;
21
22 set <int> C, D;
23 C.insert(l[0]); D.insert(l[v[0].second]);
24
25 int L = 0, R = v[0].second;
26 for (int i = 1; i < v.size(); i++)
27 {
28 int id = v[i].second;
29 int x = getDistance(id, L), y = getDistance(id, R);
30 int lcan = l[L] + x, rcan = l[R] - y, res;
31 auto it = --C.upper_bound(lcan);
32 if (y == lcan - *it + l[R] - *it)
33 {
34 res = 1;
35 }
36 else
37 {
38 auto it = D.upper_bound(rcan);
39 if (it != D.end() && x == *it - rcan + *it - l[L])
40 {
41 res = 0;
42 }
43 else
44 {
45 if (v[i].first == 2 * l[v[0].second] - first - rcan) res = 0;
46 else res = 1;
47 }
48 }
49
50 if (res == 1)
51 {
52 l[id] = lcan;
53 t[id] = 2;
54 D.insert(l[id]);
55 if (l[R] < l[id]) R = id;
56 }
57 else
58 {
59 l[id] = rcan;
60 t[id] = 1;
61 C.insert(l[id]);
62 if (l[L] > l[id]) L = id;
63 }
64 }
65 }
66
67 // ------------- begin grader ---------------------
68
69 typedef struct Station
70 {
71 int index;
72 int type;
73 int location;
74 int L,R;
75 } STATION;
CAPITOLUL 7. IOI 2014 837
76
77 long long cnt;
78 static int S,SUBTASK;
79 static STATION stations[10004];
80
81 int cmp_fun_1(const void *a,const void *b)
82 {
83 STATION c,d;
84 c = *(STATION*)(a);
85 d = *(STATION*)(b);
86 return c.location < d.location ? -1 : 1;
87 }
88
89 int cmp_fun_2(const void *a,const void *b)
90 {
91 STATION c,d;
92 c = *(STATION*)(a);
93 d = *(STATION*)(b);
94 return c.index < d.index ? -1 : 1;
95 }
96
97 void now_I_want_to_getLR()
98 {
99 int now = stations[S-1].index,i;
100 for(i=S-2;i>=0;i--)
101 {
102 stations[i].R = now;
103 if(stations[i].type==2) now = stations[i].index;
104 }
105 now = stations[0].index;
106 for(i=1;i<S;i++)
107 {
108 stations[i].L = now;
109 if(stations[i].type==1) now = stations[i].index;
110 }
111 }
112
113 int getDistance(int x,int y)
114 {
115 cnt++;
116 if(x==y) return 0;
117 if(x<0 || x>=S || y<0 || y>=S) return -1;
118 if(stations[x].location > stations[y].location)
119 {
120 int tmp = x;
121 x = y;
122 y = tmp;
123 }
124
125 int ret = 0;
126 if(stations[x].type==1 && stations[y].type==1)
127 {
128 ret = stations[stations[y].R].location-
129 stations[x].location+
130 stations[stations[y].R].location-
131 stations[y].location;
132 }
133 else
134 if(stations[x].type==1 && stations[y].type==2)
135 {
136 ret = stations[y].location-stations[x].location;
137 }
138 else
139 if(stations[x].type==2 && stations[y].type==2)
140 {
141 ret = stations[x].location-
142 stations[stations[x].L].location+
143 stations[y].location-
144 stations[stations[x].L].location;
145 }
146 else
147 if(stations[x].type==2 && stations[y].type==1)
148 {
149 ret = stations[x].location-
150 stations[stations[x].L].location+
151 stations[stations[y].R].location-
CAPITOLUL 7. IOI 2014 838
152 stations[stations[x].L].location+
153 stations[stations[y].R].location-
154 stations[y].location;
155 }
156
157 return ret;
158 }
159
160 void getInput()
161 {
162 int g;
163 g = scanf("%d",&SUBTASK);
164 g = scanf("%d",&S);
165
166 int s;
167 for (s = 0; s < S; s++)
168 {
169 int type, location;
170 g = scanf(" %d %d",&type,&location);
171 stations[s].index = s;
172 stations[s].location = location;
173 stations[s].type = type;
174 stations[s].L = -1;
175 stations[s].R = -1;
176 }
177
178 qsort(stations, S, sizeof(STATION), cmp_fun_1);
179 now_I_want_to_getLR();
180 qsort(stations, S, sizeof(STATION), cmp_fun_2);
181 }
182
183 int serverGetStationNumber()
184 {
185 return S;
186 }
187
188 int serverGetSubtaskNumber()
189 {
190 return SUBTASK;
191 }
192
193 int serverGetFirstStationLocation()
194 {
195 return stations[0].location;
196 }
197
198 int main()
199 {
200 auto t1 = clock();
201
202 std::freopen("../tests/04-020.in", "r", stdin) ;
203 //std::freopen("rail.out", "w", stdout) ;
204
205 int i;
206 getInput();
207 cnt = 0;
208
209 int location[10005];
210 int type[10005];
211 int ok = 1;
212
213 auto t2 = clock();
214
215 findLocation(S, serverGetFirstStationLocation(),location, type);
216
217 auto t3 = clock();
218
219 if(SUBTASK==3 && cnt>S*(S-1)) ok = 0;
220 if(SUBTASK==4 && cnt>3*(S-1)) ok = 0;
221
222 for (i = 0; i < S; i++)
223 if(type[i]!=stations[i].type || location[i]!=stations[i].location)
224 ok = 0;
225
226 if(ok==0) printf("Incorrect\n\n");
227 else printf("Correct\n\n");
CAPITOLUL 7. IOI 2014 839
228
229 fclose(stdout);
230
231 auto t4 = clock();
232
233 // reset console output
234 freopen("CON", "w", stdout);
235
236 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
237 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
238 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
239
240 return 0;
241 }
242 // -------------- end grader ----------------------
243 /*
244 Correct
245
246 t2-t1 = 0.031
247 t3-t2 = 0.015
248 t4-t3 = 0.016
249
250 Process returned 0 (0x0) execution time : 0.094 s
251 Press any key to continue.
252 */
48
49 if(isC)
50 {
51 l[idx]=rgcan;
52 t[idx]=1;
53 C.insert(l[idx]);
54 if(l[L]>l[idx]) L=idx;
55 }
56 else
57 {
58 l[idx]=lfcan;
59 t[idx]=2;
60 D.insert(l[idx]);
61 if(l[R]<l[idx]) R=idx;
62 }
63 }
64 }
65
66 // ------------- begin grader ---------------------
67
68 typedef struct Station
69 {
70 int index;
71 int type;
72 int location;
73 int L,R;
74 } STATION;
75
76 long long cnt;
77 static int S,SUBTASK;
78 static STATION stations[10004];
79
80 int cmp_fun_1(const void *a,const void *b)
81 {
82 STATION c,d;
83 c = *(STATION*)(a);
84 d = *(STATION*)(b);
85 return c.location < d.location ? -1 : 1;
86 }
87
88 int cmp_fun_2(const void *a,const void *b)
89 {
90 STATION c,d;
91 c = *(STATION*)(a);
92 d = *(STATION*)(b);
93 return c.index < d.index ? -1 : 1;
94 }
95
96 void now_I_want_to_getLR()
97 {
98 int now = stations[S-1].index,i;
99 for(i=S-2;i>=0;i--)
100 {
101 stations[i].R = now;
102 if(stations[i].type==2) now = stations[i].index;
103 }
104 now = stations[0].index;
105 for(i=1;i<S;i++)
106 {
107 stations[i].L = now;
108 if(stations[i].type==1) now = stations[i].index;
109 }
110 }
111
112 int getDistance(int x,int y)
113 {
114 cnt++;
115 if(x==y) return 0;
116 if(x<0 || x>=S || y<0 || y>=S) return -1;
117 if(stations[x].location > stations[y].location)
118 {
119 int tmp = x;
120 x = y;
121 y = tmp;
122 }
123
CAPITOLUL 7. IOI 2014 841
200
201 std::freopen("../tests/04-020.in", "r", stdin) ;
202 //std::freopen("rail.out", "w", stdout) ;
203
204 int i;
205 getInput();
206 cnt = 0;
207
208 int location[10005];
209 int type[10005];
210 int ok = 1;
211
212 auto t2 = clock();
213
214 findLocation(S, serverGetFirstStationLocation(),location, type);
215
216 auto t3 = clock();
217
218 if(SUBTASK==3 && cnt>S*(S-1)) ok = 0;
219 if(SUBTASK==4 && cnt>3*(S-1)) ok = 0;
220
221 for (i = 0; i < S; i++)
222 if(type[i]!=stations[i].type || location[i]!=stations[i].location)
223 ok = 0;
224
225 if(ok==0) printf("Incorrect\n\n");
226 else printf("Correct\n\n");
227
228 fclose(stdout);
229
230 auto t4 = clock();
231
232 // reset console output
233 freopen("CON", "w", stdout);
234
235 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
236 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
237 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
238
239 return 0;
240 }
241 // -------------- end grader ----------------------
242 /*
243 Correct
244
245 t2-t1 = 0.015
246 t3-t2 = 0.016
247 t4-t3 = 0
248
249 Process returned 0 (0x0) execution time : 0.078 s
250 Press any key to continue.
251 */
7.3 Wall
Problema 3 - Wall 100 de puncte
Author: Bartosz Tarnawski, Poland
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 7. IOI 2014 843
Apoi, Jian-Jia parcurge k faze ad ugând sau sc zând c r mizi. Procesul de construire a pe-
retelui se încheie atunci când toate cele k faze sunt parcurse. La ecare 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 nal 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 ecare 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 ecare 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 ecare 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 ecare coloan dup parcurgerea tuturor fazelor.
Trebuie s implementaµi funcµia buildWall.
buildWall(n, k, op, left, right, height, nalHeight)
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 nal 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 7. IOI 2014 844
Detalii de implementare
Trebuie s înc rcaµi exact un ³ier, numit wall.c, wall.cpp sau wall.pas. în acest ³ier se va
implementa funcµia descris mai sus, utilizând antetul de mai jos. De asemenea veµi include un
³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 rst.
After all queries are processed, we simply scan each position and check (with log n complexity)
the operations applied on it, obtaining the nal 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 7. IOI 2014 846
71
72 for (i = 0; i < k; i++)
73 {
74 status = scanf("%d%d%d%d", &op[i], &left[i], &right[i], &height[i]);
75 assert(status == 4);
76 }
77
78 auto t2 = clock();
79
80 buildWall(n, k, op, left, right, height, finalHeight);
81
82 auto t3 = clock();
83
84 for (j = 0; j < n; j++)
85 printf("%d\n", finalHeight[j]);
86
87 fclose(stdout);
88
89 auto t4 = clock();
90
91 // reset console output
92 freopen("CON", "w", stdout);
93
94 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
95 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
96 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
97
98 return 0;
99 }
100
101 // ------------ end grader --------------------
102 /*
103 t2-t1 = 2.422
104 t3-t2 = 2.25
105 t4-t3 = 1.016
106
107 Process returned 0 (0x0) execution time : 5.750 s
108 Press any key to continue.
109
110 argc = 4
111 checker
112 ../tests/04-030.in
113 wall.out
114 ../tests/04-030.out
115 ----------------------
116 1
117 Correct
118
119 Process returned 0 (0x0) execution time : 5.255 s
120 Press any key to continue.
121 */
93939
94 return;
95 }
96
97 // ------------ begin grader ------------------
98 int main()
99 {
100 auto t1 = clock();
101
102 std::freopen("../tests/04-030.in", "r", stdin) ;
103 std::freopen("wall.out", "w", stdout) ;
104
105 int n;
106 int k;
107
108 int i, j;
109 int status = 0;
110
111 status = scanf("%d%d", &n, &k);
112 assert(status == 2);
113
114 int* op = (int*)calloc(sizeof(int), k);
115 int* left = (int*)calloc(sizeof(int), k);
116 int* right = (int*)calloc(sizeof(int), k);
117 int* height = (int*)calloc(sizeof(int), k);
118 int* finalHeight = (int*)calloc(sizeof(int), n);
119
120 for (i = 0; i < k; i++)
121 {
122 status = scanf("%d%d%d%d", &op[i], &left[i], &right[i], &height[i]);
123 assert(status == 4);
124 }
125
126 auto t2 = clock();
127
128 buildWall(n, k, op, left, right, height, finalHeight);
129
130 auto t3 = clock();
131
132 for (j = 0; j < n; j++)
133 printf("%d\n", finalHeight[j]);
134
135 fclose(stdout);
136
137 auto t4 = clock();
138
139 // reset console output
140 freopen("CON", "w", stdout);
141
142 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
143 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
144 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
145 return 0;
146 }
147
148 // ------------ end grader --------------------
149 /*
150 t2-t1 = 2.688
151 t3-t2 = 4.484
152 t4-t3 = 1
153
154 Process returned 0 (0x0) execution time : 8.234 s
155 Press any key to continue.
156
157 argc = 4
158 checker
159 ../tests/04-030.in
160 wall.out
161 ../tests/04-030.out
162 ----------------------
163 1
164 Correct
165
166 Process returned 0 (0x0) execution time : 5.208 s
167 Press any key to continue.
168 */
CAPITOLUL 7. IOI 2014 852
75
76 status = scanf("%d%d", &n, &k);
77 assert(status == 2);
78
79 int* op = (int*)calloc(sizeof(int), k);
80 int* left = (int*)calloc(sizeof(int), k);
81 int* right = (int*)calloc(sizeof(int), k);
82 int* height = (int*)calloc(sizeof(int), k);
83 int* finalHeight = (int*)calloc(sizeof(int), n);
84
85 for (i = 0; i < k; i++)
86 {
87 status = scanf("%d%d%d%d", &op[i], &left[i], &right[i], &height[i]);
88 assert(status == 4);
89 }
90
91 auto t2 = clock();
92
93 buildWall(n, k, op, left, right, height, finalHeight);
94
95 auto t3 = clock();
96
97 for (j = 0; j < n; j++)
98 printf("%d\n", finalHeight[j]);
99
100 fclose(stdout);
101
102 auto t4 = clock();
103
104 // reset console output
105 freopen("CON", "w", stdout);
106
107 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
108 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
109 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
110
111 return 0;
112 }
113
114 // ------------ end grader --------------------
115 /*
116 t2-t1 = 0.593
117 t3-t2 = 3.922
118 t4-t3 = 0.813
119
120 Process returned 0 (0x0) execution time : 5.375 s
121 Press any key to continue.
122
123 argc = 4
124 checker
125 ../tests/04-030.in
126 wall.out
127 ../tests/04-030.out
128 ----------------------
129 1
130 Correct
131
132 Process returned 0 (0x0) execution time : 5.203 s
133 Press any key to continue.
134 */
13 (char*)"../tests/04-030.in",
14 (char*)"wall.out",
15 (char*)"../tests/04-030.out",
16 };
17
18 cout<<"argc = "<<argc<<"\n";
19 for(int kk=0;kk<argc;kk++)
20 cout<<argv[kk]<<"\n";
21 cout<<"----------------------\n";
22
23 registerChecker("wall", argc, argv);
24 compareRemainingLines();
25 }
7.4 Friend
Problema 4 - Friend 100 de puncte
Author: Sun-Yuan Hsieh, Taiwan
Dup ce construim reµeaua, dorim s select m un e³antion pentru un sondaj, ceea ce presupune
alegerea unui grup de persoane din reµea. Deoarece prietenii de obicei au interese similare, e³an-
tionul 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
asociate 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 de-
vin 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 7. IOI 2014 855
Etapele 4 ³i 5 sunt de asemenea prezentate în tabelul de mai sus. Reµeaua nal este prezen-
tat în gura 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 ec rei etape ³i valoarea încrederii asociate ec 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 nedenite ³i nu trebuie
s e 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 ³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 ³ierul header friend.h pentru implement rile C/C++.
pentru programele C/C++
int findSample(int n, int confidence[], int host[], int protocol[]);
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 condence 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.
Dene 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 nal 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 condence equals to 1, the problem becomes nding 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, conicting with the denition
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Ó nd out maximum cardinality matching in a bipartite graph,
with complexity of O N E or O N E , depending on dierent 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'. Howe-
ver, the condence 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 nally get the p; q pair for the last person. The answer will be max p; q of the last person.
Here we briey 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
39 return max(a[0],b[0]);
40 }
41
42 // ----------- begin grader --------------------
43
44 // Confidence
45 int confidence[__MAXSIZE__];
46
47 // Host
48 int host[__MAXSIZE__];
49
50 // Protocol
51 int protocol[__MAXSIZE__];
52
53 // Main
54 int main(void)
55 {
56 auto t1 = clock();
57
58 std::freopen("../tests/06-015.in", "r", stdin) ;
59 std::freopen("friend.out", "w", stdout) ;
60
61 int n,i;
62
63 // Number of people
64 assert(scanf("%d",&n)==1);
65
66 // Confidence
67 for(i=0;i<n;i++)
68 assert(scanf("%d",&confidence[i])==1);
69
70 // Host and Protocol
71 for(i=1;i<n;i++)
72 assert(scanf("%d %d",&host[i],&protocol[i])==2);
73
74 auto t2 = clock();
75
76 // Answer
77 printf("%d\n",findSample(n,confidence,host,protocol));
78 auto t3 = clock();
79
80 fclose(stdout);
81
82 auto t4 = clock();
83
84 // reset console output
85 freopen("CON", "w", stdout);
86
87 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
88 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
89 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
90
91 return 0;
92 }
93
94 // ----------- end grader ----------------------
95 /*
96 t2-t1 = 0.359
97 t3-t2 = 0.016
98 t4-t3 = 0
99
100 Process returned 0 (0x0) execution time : 0.422 s
101 Press any key to continue.
102
103 rgc = 4
104 checker
105 ../tests/06-015.in
106 friend.out
107 ../tests/06-015.out
108 ----------------------
109 1
110 Correct
111
112 Process returned 0 (0x0) execution time : 0.047 s
113 Press any key to continue.
114 */
CAPITOLUL 7. IOI 2014 860
46
47 // Confidence
48 for(i=0;i<n;i++)
49 assert(scanf("%d",&confidence[i])==1);
50
51 // Host and Protocol
52 for(i=1;i<n;i++)
53 assert(scanf("%d %d",&host[i],&protocol[i])==2);
54
55 auto t2 = clock();
56
57 // Answer
58 printf("%d\n",findSample(n,confidence,host,protocol));
59 auto t3 = clock();
60
61 fclose(stdout);
62
63 auto t4 = clock();
64
65 // reset console output
66 freopen("CON", "w", stdout);
67
68 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
69 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
70 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
71
72 return 0;
73 }
74
75 // ----------- end grader ----------------------
76 /*
77 t2-t1 = 0.469
78 t3-t2 = 0
79 t4-t3 = 0
80
81 Process returned 0 (0x0) execution time : 0.516 s
82 Press any key to continue.
83
84 argc = 4
85 checker
86 ../tests/06-015.in
87 friend.out
88 ../tests/06-015.out
89 ----------------------
90 1
91 Correct
92
93 Process returned 0 (0x0) execution time : 0.031 s
94 Press any key to continue.
95 */
7.5 Gondola
Problema 5 - Gondola 100 de puncte
Author: Michal Forisek. Slovakia
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 observat .
Vericarea unei secvenµe de gondole
Pentru primele trei subprobleme (subtask-uri) trebuie s vericaµ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 7. IOI 2014 864
Subproblemele 1, 2, 3
subproblem puncte n inputSeq
1 5 n & 100 ecare num r de la 1 la n apare exact o dat
2 5 n & 100, 000 1 & inputSeq i & n
3 10 n & 100, 000 1 & inputSeq i & 250, 000
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 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 sucient 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
subproblem puncte n gondolaSeq
4 5 n & 100 1 & gondolaSeq i & n 1
5 10 n & 1, 000 1 & gondolaSeq i & 5, 000
6 20 n & 100, 000 1 & gondolaSeq i & 250, 000
Exemple
subproblem gondolaSeq valoare returnat replacementSeq
4 (3, 1, 4) 1 (2)
4 (5, 1, 2, 3, 4) 0 ()
5 (2, 3, 4, 9, 6, 7, 1) 2 (5, 8)
Dac secvenµa dat este o secvenµ de gondole, atunci trebuie s determinaµi num rul
(care poate 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
subproblem puncte n inputSeq
7 5 4 & n & 50 1 & inputSeq i & n 3
8 15 4 & n & 50 1 & inputSeq i & 100, ³i cel puµin n 3 din
gondolele iniµiale 1, ..., n nu s-au stricat.
9 15 n & 100, 000 1 & inputSeq i & 250, 000
10 10 n & 100, 000 1 & inputSeq i & 1, 000, 000
Exemple
subproblem inputSeq valoare secvenµ de înlocuiri
returnat
7 (1, 2, 7, 6) 2 (3, 4, 5) sau (4, 5, 3)
8 (2, 3, 4, 12, 6, 7, 1) 1 (5, 8, 9, 10, 11)
9 (4, 7, 4, 7) 0 inputSeq nu este o secvenµ de gondole
10 (3, 4) 2 (1, 2) or (2, 1)
Detalii de implementare
Trebuie s înc rcaµi exact un ³ier, numit gondola.c, gondola.cpp sau gondola.pas. Acest
³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 ³ierul header gondola.h pentru implement ri C/C++.
pentru programe C/C++
int valid(int n, int inputSeq[]);
int replacement(int n, int gondolaSeq[], int replacementSeq[]);
int countReplacement(int n, int inputSeq[]);
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 - nd one solution - count all solutions) are closely related.
Subtasks 1-3
In subtask 1, once we see the rst 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 dierence is that subtask 4 allows its
inecient 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 dierent options do we have for its place? If the new
gondola is present in the nal 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
dierent 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 nd the original gondola it ultimately replaced, and
we sort these records according to the new gondola number.
CAPITOLUL 7. IOI 2014 867
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.
60 return 1LL*x*x%MOD;
61 }
62
63 int countReplacement(int n, int inputSeq[])
64 {
65 if(!valid(n,inputSeq))return 0;
66 int i,r=1;
67
68 std::sort(inputSeq,inputSeq+n);
69
70 for(i=0;i<n;i++)
71 {
72 if(inputSeq[i]<=n)continue;
73 r=1LL*r*f(n-i,inputSeq[i]-(i>0?std::max(inputSeq[i-1],n):n)-1)%MOD;
74 }
75
76 return 1LL*r*(inputSeq[0]>n?n:1)%MOD;
77 }
78
79 // -------------- begin grader ------------------
80
81 int main()
82 {
83 auto t1 = clock();
84
85 std::freopen("../tests/10-018.in", "r", stdin) ;
86 std::freopen("gondola.out", "w", stdout) ;
87
88 int i, n, tag;
89 int nr;
90
91 assert(scanf("%d", &tag)==1);
92 assert(scanf("%d", &n)==1);
93
94 for(i=0;i< n;i++)
95 assert( scanf("%d", &gondolaSequence[i]) ==1);
96
97 auto t2 = clock();
98
99 switch (tag)
100 {
101 case 1: case 2: case 3:
102 printf("%d\n", valid(n, gondolaSequence));
103 break;
104
105 case 4: case 5: case 6:
106 nr = replacement(n, gondolaSequence, replacementSequence);
107 printf("%d ", nr);
108 if (nr > 0)
109 {
110 for (i=0; i<nr-1; i++)
111 printf("%d ", replacementSequence[i]);
112 printf("%d\n", replacementSequence[nr-1]);
113 }
114 else printf("\n");
115 break;
116
117 case 7: case 8: case 9: case 10:
118 printf("%d\n", countReplacement(n, gondolaSequence));
119 break;
120 }
121
122 auto t3 = clock();
123
124 fclose(stdout);
125
126 auto t4 = clock();
127
128 // reset console output
129 freopen("CON", "w", stdout);
130
131 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
132 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
133 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
134
135 return 0;
CAPITOLUL 7. IOI 2014 869
136 }
137 // -------------- end grader --------------------
138 /*
139 t2-t1 = 0.016
140 t3-t2 = 0.031
141 t4-t3 = 0
142
143 Process returned 0 (0x0) execution time : 1.141 s
144 Press any key to continue.
145 */
63 for(i=n+1;i<=mx;i++)
64 if(ap[i])
65 {
66 replacementSeq[l++]=ap[i];
67 act++;
68 while(act<i)
69 {
70 replacementSeq[l++]=act;
71 act++;
72 }
73 }
74 return l;
75 }
76
77 //----------------------
78
79 long long expo(long long A,int B)
80 {
81 long long ret=1,p2=A;
82 for(int p=0;p<=30;p++)
83 {
84 if(((1<<p)&B))
85 ret=(1LL*ret*p2)%mod;
86 p2=(1LL*p2*p2)%mod;
87 }
88 return ret;
89 }
90
91 int countReplacement(int n, int inputSeq[])
92 {
93 long long f=0,ans=1;
94 if(!valid(n,inputSeq)) return 0;
95 bool ordered=1;
96 for(int i=1;i<=n;i++)
97 if(ap[i])
98 ordered=0;
99
100 sort(inputSeq,inputSeq+n);
101
102 for(i=n-2;i>=0;i--)
103 if(inputSeq[i]>n||inputSeq[i+1]>n)
104 {
105 f=n-1-i;if(inputSeq[i]<n) inputSeq[i]=n;
106 ans=(1LL*ans*expo(f,inputSeq[i+1]-inputSeq[i]-1))%mod;
107 }
108
109 if(ordered)
110 {
111 f=n;
112 ans=(1LL*ans*expo(f,inputSeq[0]-n-1))%mod;
113 f=n;
114 ans=(1LL*ans*f)%mod;
115 }
116 return ans;
117 }
118
119 // -------------- begin grader ------------------
120
121 int main()
122 {
123 auto t1 = clock();
124
125 std::freopen("../tests/10-018.in", "r", stdin) ;
126 std::freopen("gondola.out", "w", stdout) ;
127
128 int i, n, tag;
129 int nr;
130
131 assert(scanf("%d", &tag)==1);
132 assert(scanf("%d", &n)==1);
133
134 for(i=0;i< n;i++)
135 assert( scanf("%d", &gondolaSequence[i]) ==1);
136
137 auto t2 = clock();
138
CAPITOLUL 7. IOI 2014 871
26 }
27 x = mul(x, x);
28 y >>= 1;
29 }
30 return res;
31 }
32
33 int valid(int n, int inputSeq[])
34 {
35 vector<int> a(inputSeq, inputSeq + n);
36 sort(a.begin(), a.end());
37 if (unique(a.begin(), a.end()) != a.end())
38 {
39 return 0;
40 }
41
42 int p = min_element(inputSeq, inputSeq + n) - inputSeq;
43 for (int i = 0; i < n; ++i)
44 {
45 if (inputSeq[(p + i) % n] <= n &&
46 inputSeq[(p + i) % n] != inputSeq[p] + i)
47 {
48 return 0;
49 }
50 }
51
52 return 1;
53 }
54
55 int replacement(int n, int gondolaSeq[], int replacementSeq[])
56 {
57 int q = min_element(gondolaSeq, gondolaSeq + n) - gondolaSeq;
58 if (gondolaSeq[q] <= n)
59 {
60 q = (q - (gondolaSeq[q] - 1) + n) % n;
61 }
62
63 int p = max_element(gondolaSeq, gondolaSeq + n) - gondolaSeq;
64 int m = gondolaSeq[p];
65
66 vector<int> pos(m + 1, -1);
67 for (int i = 0; i < n; ++i)
68 {
69 pos[gondolaSeq[i]] = (i - q + n) % n + 1;
70 }
71
72 for (int i = n + 1; i <= m; ++i)
73 {
74 if (pos[i] != -1)
75 {
76 replacementSeq[i - n - 1] = pos[i];
77 }
78 else
79 {
80 replacementSeq[i - n - 1] = pos[m];
81 pos[m] = i;
82 }
83 }
84
85 return m - n;
86 }
87
88 int countReplacement(int n, int inputSeq[])
89 {
90 if (!valid(n, inputSeq))
91 {
92 return 0;
93 }
94
95 sort(inputSeq, inputSeq + n);
96
97 int ans = 1;
98 if (inputSeq[0] > n)
99 {
100 ans = n;
101 }
CAPITOLUL 7. IOI 2014 873
102
103 for (int i = 0; i < n; ++i)
104 {
105 if (inputSeq[i] > n)
106 {
107 ans = mul(ans,
108 power(n - i,
109 inputSeq[i]-max(n, i ? inputSeq[i-1] : n) - 1));
110 }
111 }
112
113 return ans;
114 }
115
116 // -------------- begin grader ------------------
117
118 int main()
119 {
120 auto t1 = clock();
121
122 std::freopen("../tests/10-018.in", "r", stdin) ;
123 std::freopen("gondola.out", "w", stdout) ;
124
125 int i, n, tag;
126 int nr;
127
128 assert(scanf("%d", &tag)==1);
129 assert(scanf("%d", &n)==1);
130
131 for(i=0;i< n;i++)
132 assert( scanf("%d", &gondolaSequence[i]) ==1);
133
134 auto t2 = clock();
135
136 switch (tag)
137 {
138 case 1: case 2: case 3:
139 printf("%d\n", valid(n, gondolaSequence));
140 break;
141
142 case 4: case 5: case 6:
143 nr = replacement(n, gondolaSequence, replacementSequence);
144 printf("%d ", nr);
145 if (nr > 0)
146 {
147 for (i=0; i<nr-1; i++)
148 printf("%d ", replacementSequence[i]);
149 printf("%d\n", replacementSequence[nr-1]);
150 }
151 else printf("\n");
152 break;
153
154 case 7: case 8: case 9: case 10:
155 printf("%d\n", countReplacement(n, gondolaSequence));
156 break;
157 }
158
159 auto t3 = clock();
160
161 fclose(stdout);
162
163 auto t4 = clock();
164
165 // reset console output
166 freopen("CON", "w", stdout);
167
168 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
169 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
170 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
171
172 return 0;
173 }
174 // -------------- end grader --------------------
175 /*
176 t2-t1 = 0.063
177 t3-t2 = 0.046
CAPITOLUL 7. IOI 2014 874
178 t4-t3 = 0
179
180 Process returned 0 (0x0) execution time : 1.844 s
181 Press any key to continue.
182 */
68 while(A[q]!=p)
69 {
70 B[ret++]=A[q];
71 A[q]=now++;
72 }
73 }
74 return ret;
75 }
76
77 ll mypow(ll x, ll y)
78 {
79 if(y==0) return 1;
80
81 if(y%2) return mypow(x, y-1)*x%MOD;
82
83 ll ret=mypow(x, y/2);
84 return ret*ret%MOD;
85 }
86
87 int countReplacement(int N, int *A)
88 {
89 int i, j; ll ans=1;
90 if(!valid(N, A)) return 0;
91
92 int flag=-1;
93 vector<int> V; V.push_back(N);
94 for(i=0; i<N; i++)
95 {
96 if(A[i]<=N) flag=0;
97 else V.push_back(A[i]);
98 }
99
100 sort(V.begin(), V.end());
101 for(i=1; i<V.size(); i++)
102 ans=ans*mypow(V.size()-i, V[i]-V[i-1]-1)%MOD;
103
104 if(flag==-1) ans=ans*N%MOD;
105 return ans;
106 }
107
108 // -------------- begin grader ------------------
109
110 int main()
111 {
112 auto t1 = clock();
113
114 std::freopen("../tests/10-018.in", "r", stdin) ;
115 std::freopen("gondola.out", "w", stdout) ;
116
117 int i, n, tag;
118 int nr;
119
120 assert(scanf("%d", &tag)==1);
121 assert(scanf("%d", &n)==1);
122
123 for(i=0;i< n;i++)
124 assert( scanf("%d", &gondolaSequence[i]) ==1);
125
126 auto t2 = clock();
127
128 switch (tag)
129 {
130 case 1: case 2: case 3:
131 printf("%d\n", valid(n, gondolaSequence));
132 break;
133
134 case 4: case 5: case 6:
135 nr = replacement(n, gondolaSequence, replacementSequence);
136 printf("%d ", nr);
137 if (nr > 0)
138 {
139 for (i=0; i<nr-1; i++)
140 printf("%d ", replacementSequence[i]);
141 printf("%d\n", replacementSequence[nr-1]);
142 }
143 else printf("\n");
CAPITOLUL 7. IOI 2014 876
144 break;
145
146 case 7: case 8: case 9: case 10:
147 printf("%d\n", countReplacement(n, gondolaSequence));
148 break;
149 }
150
151 auto t3 = clock();
152
153 fclose(stdout);
154
155 auto t4 = clock();
156
157 // reset console output
158 freopen("CON", "w", stdout);
159
160 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
161 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
162 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
163
164 return 0;
165 }
166 // -------------- end grader --------------------
167 /*
168 t2-t1 = 0.078
169 t3-t2 = 0.062
170 t4-t3 = 0
171
172 Process returned 0 (0x0) execution time : 1.625 s
173 Press any key to continue.
174 */
7.6 Holiday
Problema 6 - Holiday 100 de puncte
Author: Jakub Lacki, Poland
CAPITOLUL 7. IOI 2014 877
Jian-Jia planic 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 ecare 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 a , 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 planice 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 ecare ora³ este nenegativ.
Constrângeri adiµionale:
CAPITOLUL 7. IOI 2014 878
Detalii de implementare
Trebuie s înc rcaµi un singur ³ier, cu numele holiday.c, holiday.cpp sau holiday.pas.
Acest ³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 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++
long long int findMaxAttraction(int n, int start, int d,
int attraction[]);
For ease of description, we will rst 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 xed 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 xed 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 ag indicating whether this leaf is active or not,
CAPITOLUL 7. IOI 2014 879
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 o
any leaf. It also takes O log n time to nd 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 nd 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 nd 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 rst nd 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 rst 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 o 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 rst move right to a city, then move left from this point, and then nally stop at a city
left of start. Or we rst move left to a city, then move right from this point, and then nally stop
at a city right of start. That is, we only change the direction once.
Without lost of generality, we assume the rst scenario. We rst use the immediately solution
to nd f t for all possible of values t. Then we also use the immediately solution to nd 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 rst 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.
32 else
33 {
34 int tm = (tl + tr) >> 1;
35 if(pos <= tm)
36 {
37 if(!t[v].l) t[v].l = ++ cn;
38 t[v].r = t[ov].r;
39 upd(t[ov].l, t[v].l, pos, tl, tm);
40 }
41 else
42 {
43 if(!t[v].r) t[v].r = ++ cn;
44 t[v].l = t[ov].l;
45 upd(t[ov].r, t[v].r, pos, tm + 1, tr);
46 }
47
48 t[v].cnt = t[ t[v].l ].cnt + t[ t[v].r ].cnt;
49 t[v].sum = t[ t[v].l ].sum + t[ t[v].r ].sum;
50 }
51 }
52
53 long long get(int ov, int v, int cnt, int tl = 0, int tr = sz)
54 {
55 if(cnt <= 0) return 0ll;
56 if(tl == tr)
57 {
58 long long k = min(t[v].cnt - t[ov].cnt, cnt);
59 return k * 1ll * vec[tl];
60 }
61
62 int tm = (tl + tr) >> 1;
63 int k = t[ t[v].r ].cnt - t[ t[ov].r ].cnt;
64 if(k <= cnt)
65 return t[ t[v].r ].sum -
66 t[ t[ov].r ].sum +
67 get(t[ov].l, t[v].l, cnt - k, tl, tm);
68
69 return get(t[ov].r, t[v].r, cnt, tm + 1, tr);
70 }
71
72 void calc(int l, int r, int opl, int opr)
73 {
74 if(l > r) return ;
75 int md = (l + r) >> 1, opt = -1;
76 long long ret = -1;
77 for(int i = opl; i <= opr; i ++)
78 {
79 int lenA = (start - md), lenB = (i - start);
80 int cnt = d - lenA - lenB - min(lenA, lenB);
81 long long now = get(root[md], root[i + 1], cnt);
82 if(ret < now)
83 {
84 ret = now;
85 opt = i;
86 }
87 }
88
89 ans = max(ans, ret);
90 calc(l, md - 1, opl, opt);
91 calc(md + 1, r, opt, opr);
92 }
93
94 long long int findMaxAttraction(int n, int startS, int D, int ar[])
95 {
96 d = D;
97 start = startS;
98 vec.push_back(-2e9);
99 for(int i = 0; i < n; i ++)
100 {
101 vec.push_back(ar[i]);
102 }
103
104 sort(vec.begin(),vec.end());
105
106 vec.resize(unique(vec.begin(), vec.end()) - vec.begin());
107
CAPITOLUL 7. IOI 2014 884
108 sz = (int)vec.size() - 1;
109 for(int i = 0; i < n; i ++)
110 {
111 ar[i] = lower_bound(vec.begin(),vec.end(), ar[i])-vec.begin();
112 }
113
114 for(int i = 1; i <= n; i ++)
115 {
116 root[i] = ++ cn;
117 upd(root[i - 1], root[i], ar[i - 1]);
118 }
119
120 calc(0, start, start, n);
121
122 return ans;
123 }
124
125 // ----------- begin grader -------------
126
127 int main()
128 {
129 auto t1 = clock();
130
131 std::freopen("../tests/04-009.in", "r", stdin) ;
132 std::freopen("holiday.out", "w", stdout) ;
133
134 int n, start, d;
135 int attraction[100000];
136 int i, n_s;
137
138 n_s = scanf("%d %d %d", &n, &start, &d);
139 for (i = 0 ; i < n; ++i)
140 {
141 n_s = scanf("%d", &attraction[i]);
142 }
143
144 auto t2 = clock();
145
146 printf("%lld\n", findMaxAttraction(n, start, d, attraction));
147
148 auto t3 = clock();
149
150 fclose(stdout);
151
152 auto t4 = clock();
153
154 // reset console output
155 freopen("CON", "w", stdout);
156
157 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
158 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
159 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
160
161 return 0;
162 }
163
164 // ---------- end grader ----------------
165 /*
166 t2-t1 = 0.187
167 t3-t2 = 0.938
168 t4-t3 = 0
169
170 Process returned 0 (0x0) execution time : 1.234 s
171 Press any key to continue.
172 */
94 ll get(int l, int r)
95 {
96 int go = (start - l) + (r - start) + min(start - l, r - start);
97 if (hol <= go)
98 return 0;
99 int k = hol - go;
100
101 return sum(t[l], t[r + 1], 0, N, min(r - l + 1, k));
102 }
103
104 int get_opt(int r, int opt_l, int opt_r)
105 {
106 ll nn = 0, opt = opt_l;
107 for (int l = opt_l; l <= opt_r; ++l)
108 {
109 ll t = get(l, r);
110 if (t > nn)
111 {
112 nn = t;
113 opt = l;
114 }
115 }
116
117 ans = max(ans, nn);
118 return opt;
119 }
120
121 void solve(int l, int r, int opt_l, int opt_r)
122 {
123 if (r < l)
124 return;
125 int m = (l + r) >> 1;
126 int opt_m = get_opt(m, opt_l, opt_r);
127
128 solve(l, m - 1, opt_l, opt_m);
129 solve(m + 1, r, opt_m, opt_r);
130 }
131
132 long long int findMaxAttraction(int n, int start_, int hol_, int a_[])
133 {
134 for (int i = 0; i < V; ++i)
135 {
136 d[i].cnt = d[i].sum = 0;
137 d[i].l = d[i].r = -1;
138 }
139
140 start = start_;
141 hol = hol_;
142 for (int i = 0; i < n; ++i)
143 a[i] = a_[i];
144
145 for (int i = 0; i < n; ++i)
146 c.app(a[i]);
147
148 sort(all(c));
149 c.resize(unique(all(c)) - c.begin());
150
151 for (int i = 0; i < n; ++i)
152 a[i] = lower_bound(all(c), a[i]) - c.begin();
153
154 t[0] = build(0, N);
155 for (int i = 0; i < n; ++i)
156 t[i + 1] = add(t[i], 0, N, a[i]);
157
158 solve(start, n - 1, 0, start);
159 return ans;
160 }
161
162 // ----------- begin grader -------------
163
164 int main()
165 {
166 auto t1 = clock();
167
168 std::freopen("../tests/04-009.in", "r", stdin) ;
169 std::freopen("holiday.out", "w", stdout) ;
CAPITOLUL 7. IOI 2014 889
170
171 int n, start, d;
172 int attraction[100000];
173 int i, n_s;
174
175 n_s = scanf("%d %d %d", &n, &start, &d);
176 for (i = 0 ; i < n; ++i)
177 {
178 n_s = scanf("%d", &attraction[i]);
179 }
180
181 auto t2 = clock();
182
183 printf("%lld\n", findMaxAttraction(n, start, d, attraction));
184
185 auto t3 = clock();
186
187 fclose(stdout);
188
189 auto t4 = clock();
190
191 // reset console output
192 freopen("CON", "w", stdout);
193
194 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
195 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
196 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
197
198 return 0;
199 }
200
201 // ---------- end grader ----------------
202 /*
203 t2-t1 = 0.187
204 t3-t2 = 1.156
205 t4-t3 = 0
206
207 Process returned 0 (0x0) execution time : 1.391 s
208 Press any key to continue.
209 */
IOI 201333
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 un exemplu din una dintre 4
stiluri distincte, numerotate 1, 2, 3 ³i 4.
Primul stil conµine art modern neoplazic . De exemplu:
891
CAPITOLUL 8. IOI 2013 892
Dat ind 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 ecare stil. Nou imagini din ecare 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 date programului t u în timpul
grad rii.
Imaginea va 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 ec 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 ³ier ce implementeaz functia travelTime(), dup cum ur-
meaz :
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 ecare pixel al imaginii.
G : O matrice de m rime H W ce conµine cantitatea de verde din ecare pixel al imaginii.
B : O matrice de m rime H W ce conµine cantitatea de albastru din ecare pixel al
imaginii.
Returneaz : Stilului imaginii, care poate 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 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 calculat pe baza num -
rului de imagini pe care programul vostru le clasic corect.
Presupunând c veµi clasica corect un procent de P imagini (deci 0 & P & 100):
CAPITOLUL 8. IOI 2013 893
Testare
Grader-ul de pe computerul vostru va citi input-ul din ³ierul artclass.jpg. Acest ³ier
trebuie sa conµin o imagine în format JPEG.
V este permis s folosiµi orice aplicaµie de procesare grac 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 deniµ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 nd 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 frequ-
encies.
For the downsample and upsample I took a simple box lter. 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 dierences from the means, with the dierences
scaled using the standard deviations. It's not 100% accurate, but good enough to get a perfect
score.
8.2 Cave
Problema 2 - Cave 100 de puncte
Authors: Amaury Pouly and Arthur Charguéraud (France)
CAPITOLUL 8. IOI 2013 894
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, aate una în spatele alteia ³i N întrerup toare,
ecare întrerup tor conectat la o u³ diferit .
U³ile sunt numerotate 0, 1, ..., N 1 în ordine, u³a 0 ind cea mai apropiat de voi.
Întrerup toarele sunt de asemenea numerotate 0, 1, ..., N 1, dar nu cunoa³teµi care întreru-
p tor este conectat la care u³ .
Întrerup toarele se a la intrarea în pe³ter . Fiecare întrerup tor poate în poziµia up sau
în poziµia down. Numai una din aceste poziµii este corect pentru ecare î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 a în poziµia gre³ita atunci u³a la care este conectat nu se va deschide. Poziµia
corect poate 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 a 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 ecare întrerup tor ³i cu care u³ este conectat
ecare întrerup tor.
Implementare
Va trebui s submitaµi un ³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++
int tryCombination(int S[]);
Pascal
function tryCombination(var S: array of LongInt) : LongInt;
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 apelat de maxim 70,000 de ori.
Parametrii
S : Un array de dimensiune N , indicând poziµia ecarui întrerup tor. Elementul S i cores-
punde cu întrerup torul i. O valoare de 0 indic faptul c întrerup torul este în poziµia de
up, iar o valoare de 1 indic faptul c este în poziµia de down.
Returneaz : Num rul primei u³i care este închis , sau -1 dac toate u³ile sunt deschise.
CAPITOLUL 8. IOI 2013 895
Pascal
procedure answer(var S, D: array of LongInt);
Descriere
Apelaµi acest procedur atunci când aµi identicat o combinaµie de întrerup toare care s
deschid toate u³ile, ³i u³a la care este conectat ecare întrerup tor.
Parametrii
S : Un array de lungime N , indicând poziµia corect a ec 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 ecare î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
procedure exploreCave(N: longint);
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 ec rui întrerup tor, ³i u³a la care este conectat ecare întrerup tor,
iar apoi, când are aceste informaµii, s apeleze answer().
Parametrii
N : Num rul de întrerup toare ³i u³i din pe³ter .
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 întreru-
p 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 8. IOI 2013 896
Subtask-uri
Subtask Punctaj Constrângeri adiµionale
1 12 Pentru ecare 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 tot timpul [0, 0, 0, ..., 0].
Task-ul vostru este s determinaµi cu ce u³ este conectat ecare în-
trerup 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 ³ierul cave.in, care trebuie
s e î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 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 deniµ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 eciency. 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.
75 int correct = 1;
76 for (i = 0; i < N; ++i)
77 if (S[i] != realS[i] || D[i] != realD[i])
78 {
79 correct = 0;
80 break;
81 }
82
83 for (i = 0; i < N; ++i)
84 {
85 if (i > 0)
86 printf(" ");
87 printf("%d", S[i]);
88 }
89 printf("\n");
90
91 for (i = 0; i < N; ++i)
92 {
93 if (i > 0)
94 printf(" ");
95 printf("%d", D[i]);
96 }
97 printf("\n");
98
99 //exit(0);
100 }
101
102 int tryCombination(int S[])
103 {
104 int i;
105
106 if (num_calls >= MAX_CALLS)
107 {
108 printf("INCORRECT\nToo many calls to tryCombination().\n");
109 exit(0);
110 }
111 ++num_calls;
112
113 for (i = 0; i < N; ++i)
114 if (S[inv[i]] != realS[inv[i]])
115 return i;
116 return -1;
117 }
118
119 int init()
120 {
121 int i, res;
122
123 res = scanf("%d", &N);
124
125 for (i = 0; i < N; ++i)
126 {
127 res = scanf("%d", &realS[i]);
128 }
129 for (i = 0; i < N; ++i)
130 {
131 res = scanf("%d", &realD[i]);
132 inv[realD[i]] = i;
133 }
134
135 num_calls = 0;
136 return N;
137 }
138
139 int main()
140 {
141 auto t1 = clock();
142
143 std::freopen("../tests/random-perm-5000-many-closed.in", "r", stdin);
144 std::freopen("cave.out", "w", stdout);
145
146 int N;
147
148 N = init();
149
150 auto t2 = clock();
CAPITOLUL 8. IOI 2013 899
151
152 exploreCave(N);
153
154 auto t3 = clock();
155
156 auto t4 = clock();
157
158 // reset console output
159 freopen("CON", "w", stdout);
160
161 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
162 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
163 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
164
165 return 0;
166 }
167 /*
168 t2-t1 = 0.053
169 t3-t2 = 1.487
170 t4-t3 = 0
171
172 Process returned 0 (0x0) execution time : 1.650 s
173 Press any key to continue.
174 */
125 {
126 res = scanf("%d", &realD[i]);
127 inv[realD[i]] = i;
128 }
129
130 num_calls = 0;
131 return N;
132 }
133
134 int main()
135 {
136 auto t1 = clock();
137
138 std::freopen("../tests/random-perm-5000-many-closed.in", "r", stdin);
139 std::freopen("cave.out", "w", stdout);
140
141 int N;
142
143 N = init();
144
145 auto t2 = clock();
146
147 exploreCave(N);
148
149 auto t3 = clock();
150
151 auto t4 = clock();
152
153 // reset console output
154 freopen("CON", "w", stdout);
155
156 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
157 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
158 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
159
160 return 0;
161 }
162 /*
163 t2-t1 = 0
164 t3-t2 = 1.791
165 t4-t3 = 0
166
167 Process returned 0 (0x0) execution time : 1.899 s
168 Press any key to continue.
169 */
28 else pr = false;
29 int maxi = N, mini = -1;
30 while(maxi - mini > 1)
31 {
32 int medi = (maxi + mini) / 2;
33 for (int j = mini + 1; j <= medi; j++)
34 {
35 if (c[j]) continue;
36 s[j] = !s[j];
37 }
38 res = tryCombination(s);
39 if (res == -1 or res > i) dw = true;
40 else dw = false;
41 if (dw == pr) mini = medi;
42 else maxi = medi;
43 pr = dw;
44 }
45
46 d[maxi] = i;
47 c[maxi] = true;
48 if(!dw)
49 {
50 s[maxi] = !s[maxi];
51 res = tryCombination(s);
52 }
53 }
54 answer(s, d);
55 }
56
57 // -------- end exploreCave(int N) -----------------
58
59 #define MAX_N 5000
60 #define MAX_CALLS 70000
61
62 #define fail(s, x...) do { \
63 fprintf(stderr, s "\n", ## x); \
64 exit(1); \
65 } while(0)
66
67 /* Symbol obfuscation */
68 #define N koala
69 #define realS kangaroo
70 #define realD possum
71 #define inv platypus
72 #define num_calls echidna
73
74 static int N;
75 static int realS[MAX_N];
76 static int realD[MAX_N];
77 static int inv[MAX_N];
78 static int num_calls;
79
80 void answer(int S[], int D[])
81 {
82 int i;
83 int correct = 1;
84 for (i = 0; i < N; ++i)
85 if (S[i] != realS[i] || D[i] != realD[i])
86 {
87 correct = 0;
88 break;
89 }
90
91 for (i = 0; i < N; ++i)
92 {
93 if (i > 0)
94 printf(" ");
95 printf("%d", S[i]);
96 }
97 printf("\n");
98
99 for (i = 0; i < N; ++i)
100 {
101 if (i > 0)
102 printf(" ");
103 printf("%d", D[i]);
CAPITOLUL 8. IOI 2013 903
104 }
105 printf("\n");
106
107 //exit(0);
108 }
109
110 int tryCombination(int S[])
111 {
112 int i;
113
114 if (num_calls >= MAX_CALLS)
115 {
116 printf("INCORRECT\nToo many calls to tryCombination().\n");
117 exit(0);
118 }
119 ++num_calls;
120
121 for (i = 0; i < N; ++i)
122 if (S[inv[i]] != realS[inv[i]])
123 return i;
124 return -1;
125 }
126
127 int init()
128 {
129 int i, res;
130
131 res = scanf("%d", &N);
132
133 for (i = 0; i < N; ++i)
134 {
135 res = scanf("%d", &realS[i]);
136 }
137 for (i = 0; i < N; ++i)
138 {
139 res = scanf("%d", &realD[i]);
140 inv[realD[i]] = i;
141 }
142
143 num_calls = 0;
144 return N;
145 }
146
147 int main()
148 {
149 auto t1 = clock();
150
151 std::freopen("../tests/random-perm-5000-many-closed.in", "r", stdin);
152 std::freopen("cave.out", "w", stdout);
153
154 int N;
155
156 N = init();
157
158 auto t2 = clock();
159
160 exploreCave(N);
161
162 auto t3 = clock();
163
164 auto t4 = clock();
165
166 // reset console output
167 freopen("CON", "w", stdout);
168
169 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
170 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
171 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
172
173 return 0;
174 }
175 /*
176 t2-t1 = 0
177 t3-t2 = 1.671
178 t4-t3 = 0
179
CAPITOLUL 8. IOI 2013 904
146 //exit(0);
147 }
148
149 int tryCombination(int S[])
150 {
151 int i;
152
153 if (num_calls >= MAX_CALLS)
154 {
155 printf("INCORRECT\nToo many calls to tryCombination().\n");
156 exit(0);
157 }
158 ++num_calls;
159
160 for (i = 0; i < N; ++i)
161 if (S[inv[i]] != realS[inv[i]])
162 return i;
163 return -1;
164 }
165
166 int init()
167 {
168 int i, res;
169
170 res = scanf("%d", &N);
171
172 for (i = 0; i < N; ++i)
173 {
174 res = scanf("%d", &realS[i]);
175 }
176 for (i = 0; i < N; ++i)
177 {
178 res = scanf("%d", &realD[i]);
179 inv[realD[i]] = i;
180 }
181
182 num_calls = 0;
183 return N;
184 }
185
186 int main()
187 {
188 auto t1 = clock();
189
190 std::freopen("../tests/random-perm-5000-many-closed.in", "r", stdin);
191 std::freopen("cave.out", "w", stdout);
192
193 int N;
194
195 N = init();
196
197 auto t2 = clock();
198
199 exploreCave(N);
200
201 auto t3 = clock();
202
203 //printf("INCORRECT\nYour solution did not call answer().\n");
204
205 auto t4 = clock();
206
207 // reset console output
208 freopen("CON", "w", stdout);
209
210 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
211 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
212 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
213
214 return 0;
215 }
216 /*
217 t2-t1 = 0
218 t3-t2 = 1.968
219 t4-t3 = 0
220
221 Process returned 0 (0x0) execution time : 2.078 s
CAPITOLUL 8. IOI 2013 907
8.3 Dreaming
Problema 3 - Dreaming 100 de puncte
Author: Kazuhiro Hosaka (Japan)
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 e conectate deloc (deci, M & N 1). Fiecare potec necesit un num r de
zile pentru ca Serpent s o parcurg : acest num r poate diferit pentru ecare potec în parte.
Prietenul lui Serpent, Kangaroo, dore³te s construiasc N M 1 noi poteci, astfel încât s
e posibil ca Serpent s c l toreasc între oricare pereche de b ltoace. Kangaroo poate crea poteci
între oricare pereche de b ltoace, iar ecare 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 e 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 8. IOI 2013 908
Imaginea de mai sus arat setul nal 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 ³ier ce implementeaz functia travelTime(), dup cum urmeaz :
Funcµia voastr : travelTime()
C/C++
int travelTime(int N, int M, int L,
int A[], int B[], int T[]);
Pascal
function travelTime(N, M, L : LongInt;
var A, B, T : array of LongInt) : LongInt;
Descriere
CAPITOLUL 8. IOI 2013 909
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 specic capetele ³i timpul de parcurgere pentru
ecare 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 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
ecare b ltoac . Cu alte cuvinte, exist dou seturi de b ltoace conectate,
³i in ecare 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 ecare b ltoac .
5 12 N & 3, 000
6 23 (Nimic)
Testare
Grader-ul de pe computerul vostru va citi input-ul din ³ierul dreaming.in, care trebuie s
e în urm torul format:
linia 1: N M 4L4
12 8 2
0 8 4
8 2 2
2 7 4
5 11 3
5 1 7
CAPITOLUL 8. IOI 2013 910
1 3 1
1 9 5
10 6 3
Note de limbaj
C/C++: Trebuie s faceµi #include "dreaming.h".
Pascal: Trebuie s deniµ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 dierent 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 rst 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.
98 N=Nn,M=Mm,L=Ll;
99 int i;
100 for(i=0;i<M;i++)
101 {
102 edge[A[i]+1].push_back(line(B[i]+1,T[i]));
103 edge[B[i]+1].push_back(line(A[i]+1,T[i]));
104 }
105
106 for(i=1;i<=N;i++)
107 {
108 if(check[i])continue;
109 solve(i);
110 }
111 sort(Y,Y+tl);
112
113 if(tl==1)return inl;
114 if(tl==2)
115 return max(inl,L+Y[tl-1]+Y[tl-2]);
116 else
117 return max(inl,max(L+Y[tl-1]+Y[tl-2],2*L+Y[tl-2]+Y[tl-3]));
118 }
119
120 // ------------- begin grader --------------
121
122 #define fail(s, x...) do { \
123 fprintf(stderr, s "\n", ## x); \
124 exit(1); \
125 } while(0)
126
127 #define MAX_N 100000
128
129 static int A[MAX_N];
130 static int B[MAX_N];
131 static int T[MAX_N];
132
133 int main()
134 {
135 auto t1 = clock();
136
137 std::freopen("../tests/two-sticks-9.in", "r", stdin) ;
138 std::freopen("dreaming.out", "w", stdout) ;
139
140 int N, M, L, i;
141 int res;
142
143 res = scanf("%d%d%d", &N, &M, &L);
144
145 for (i = 0; i < M; i++)
146 res = scanf("%d%d%d", &A[i], &B[i], &T[i]);
147
148 auto t2 = clock();
149
150 int answer = travelTime(N, M, L, A, B, T);
151
152 auto t3 = clock();
153
154 printf("%d\n", answer);
155
156 auto t4 = clock();
157
158 // reset console output
159 freopen("CON", "w", stdout);
160
161 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
162 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
163 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
164
165 return 0;
166 }
167
168 // ------------- end grader ----------------
169 /*
170 t2-t1 = 0.093
171 t3-t2 = 0.188
172 t4-t3 = 0
173
CAPITOLUL 8. IOI 2013 913
70 d[1][x]=s;
71 v[1][x]=-1;
72 }
73
74 ret=d[0][x];
75 ch[x]=true;
76
77 for(i=sta[x];i;i=nxt[i])
78 {
79 if(chi[i]!=p)
80 {
81 int k;
82 if(v[0][x]!=i)
83 {
84 k=DFS2(chi[i],d[0][x]+wei[i],x);
85 }
86 else
87 {
88 k=DFS2(chi[i],d[1][x]+wei[i],x);
89 }
90
91 ret=min(ret,k);
92 }
93 }
94
95 itr=max(itr,d[0][x]+d[1][x]);
96 return ret;
97 }
98
99 int travelTime(int _n, int _m, int _l, int A[], int B[], int T[])
100 {
101 int i;
102 n=_n;
103 l=_l;
104 m=0;
105 for(i=0;i<_m;i++)
106 {
107 addEdge(A[i],B[i],T[i]);
108 addEdge(B[i],A[i],T[i]);
109 }
110
111 for(i=0;i<n;i++)
112 {
113 if(!ch[i])
114 {
115 DFS1(i,-1);
116 vec.push_back(DFS2(i,0,-1));
117 }
118 }
119
120 int mx1=-1,mx2=-1,mx3=-1;
121 for(i=0;i<vec.size();i++)
122 {
123 if(mx3<vec[i]){mx3=vec[i];}
124 if(mx2<vec[i]){mx3=mx2;mx2=vec[i];}
125 if(mx1<vec[i]){mx2=mx1;mx1=vec[i];}
126 }
127 if(mx2==-1) return itr;
128 if(mx3==-1) return max(itr,mx1+mx2+l);
129
130 return max(itr,max(mx1+mx2+l,mx2+mx3+l*2));
131 }
132
133 // ------------- begin grader --------------
134
135 #define fail(s, x...) do { \
136 fprintf(stderr, s "\n", ## x); \
137 exit(1); \
138 } while(0)
139
140 #define MAX_N 100000
141
142 static int A[MAX_N];
143 static int B[MAX_N];
144 static int T[MAX_N];
145
CAPITOLUL 8. IOI 2013 915
29 f(go);
30 t=M[go]+knr;
31 if(M[x]<t)
32 {
33 M2[x]=M[x];
34 M[x]=t;
35 node[x]=go;
36 }
37 else
38 if(M2[x]<t)
39 {
40 M2[x]=t;
41 }
42 }
43
44 ss=max(ss,M[x]+M2[x]);
45 }
46
47 void g(int x,int p,int t)
48 {
49 mn=min(mn,max(M[x],t));
50 for(int i=0;i<(int)v[x].size();i++)
51 {
52 int go=v[x][i].fi;
53 int knr=v[x][i].se;
54 if(go==p) continue;
55 int a=max(t,node[x]==go?M2[x]:M[x]);
56 g(go,x,a+knr);
57 }
58 }
59
60 int travelTime(int n,int m,int l,int *A,int *B,int *T)
61 {
62 int t,x,xx,xxx;
63 for(int i=0;i<m;i++)
64 {
65 v[A[i]].pb(mp(B[i],T[i]));
66 v[B[i]].pb(mp(A[i],T[i]));
67 }
68
69 x=-inf,xx=-inf,xxx=-inf;
70 for(int i=0;i<n;i++)
71 {
72 if(vis[i]==1) continue;
73 mn=1e9;
74 f(i);
75 g(i,-1,0);
76 if(x<mn)
77 {
78 xxx=xx;
79 xx=x;
80 x=mn;
81 }
82 else
83 if(xx<mn)
84 {
85 xxx=xx;
86 xx=mn;
87 }
88 else
89 if(xxx<mn)
90 {
91 xxx=mn;
92 }
93 }
94
95 return max(ss,max(x+xx+l,xx+xxx+l+l));
96 }
97
98 // ------------- begin grader --------------
99
100 #define fail(s, x...) do { \
101 fprintf(stderr, s "\n", ## x); \
102 exit(1); \
103 } while(0)
104
CAPITOLUL 8. IOI 2013 917
99
100 auto t3 = clock();
101
102 printf("%d\n", answer);
103
104 auto t4 = clock();
105
106 // reset console output
107 freopen("CON", "w", stdout);
108
109 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
110 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
111 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
112
113 return 0;
114 }
115
116 // ------------- end grader ----------------
117 /*
118 t2-t1 = 0.406
119 t3-t2 = 0.234
120 t4-t3 = 0
121
122 Process returned 0 (0x0) execution time : 2.813 s
123 Press any key to continue.
124 */
47
48 sort(v.begin(), v.end());
49 reverse(v.begin(), v.end());
50
51 if(v.size()>2)
52 {
53 ans=L+v[0]+v[1];
54 for(int i=2; i<v.size(); i++)
55 ans=max(ans, 2*L+v[1]+v[i]);
56 }
57 else
58 if(v.size()==2) ans=L+v[0]+v[1];
59 else ans=0;
60
61 ans=max(ans, diameter);
62 return ans;
63 }
64
65 // ------------- begin grader --------------
66
67 #define fail(s, x...) do { \
68 fprintf(stderr, s "\n", ## x); \
69 exit(1); \
70 } while(0)
71
72 #define MAX_N 100000
73
74 static int A[MAX_N];
75 static int B[MAX_N];
76 static int T[MAX_N];
77
78 int main()
79 {
80 auto t1 = clock();
81
82 std::freopen("../tests/two-sticks-9.in", "r", stdin) ;
83 std::freopen("dreaming.out", "w", stdout) ;
84
85 int N, M, L, i;
86 int res;
87
88 res = scanf("%d%d%d", &N, &M, &L);
89
90 for (i = 0; i < M; i++)
91 res = scanf("%d%d%d", &A[i], &B[i], &T[i]);
92
93 auto t2 = clock();
94
95 int answer = travelTime(N, M, L, A, B, T);
96
97 auto t3 = clock();
98
99 printf("%d\n", answer);
100
101 auto t4 = clock();
102
103 // reset console output
104 freopen("CON", "w", stdout);
105
106 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
107 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
108 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
109
110 return 0;
111 }
112
113 // ------------- end grader ----------------
114 /*
115 t2-t1 = 0.438
116 t3-t2 = 0.234
117 t4-t3 = 0
118
119 Process returned 0 (0x0) execution time : 2.891 s
120 Press any key to continue.
121 */
CAPITOLUL 8. IOI 2013 921
8.4 Game
Problema 4 - Game 100 de puncte
Author: Monika Steinová (Slovakia)
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.
Grid-ul rezultat este a³at în imaginea de mai sus. Bazza poate s întrebe care este CMMDC-ul
urm toarelor zone dreptunghiulare:
CAPITOLUL 8. IOI 2013 922
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 a³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.
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 ³ierul game.in. Acest ³ier trebuie s
aib urm torul format:
linia 1: R C N
urm toarele N linii: o acµiune pe linie, în ordinea în care apar
CAPITOLUL 8. IOI 2013 924
2 3 9
1 0 0 20
1 0 2 15
1 1 1 12
2 0 0 0 2
2 0 0 1 1
1 0 1 6
1 1 1 14
2 0 0 0 2
2 0 0 1 1
Note de limbaj
C/C++ Trebuie s faceµi #include "game.h".
Pascal Trebuie sa deniµi unit Game. Toµi vectorii sunt indexaµi incepând de la 0 (nu de la
1).
Deoarece întregii din grid pot 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 renement 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 t 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.
151
152 ST()
153 {
154 l = r = nullptr;
155 }
156
157 ST(int st, int en)
158 {
159 l = r = nullptr;
160 b = st, e = en;
161 }
162
163 void fix(int pos)
164 {
165 long long val = 0;
166 if (l) val = __gcd(val, l->t.query(pos, pos));
167 if (r) val = __gcd(val, r->t.query(pos, pos));
168 t.insert(pos, val);
169 }
170
171 void upd(int x, int y, long long val) //set a[x][y] = val
172 {
173 if (e < x || x < b) return;
174 if (b == e)
175 {
176 t.insert(y, val);
177 return;
178 }
179
180 if (b != e)
181 {
182 if (x <= (b + e) / 2)
183 {
184 if (!l) l = new ST(b, (b + e) / 2);
185 l->upd(x, y, val);
186 }
187 else
188 {
189 if (!r) r = new ST((b + e) / 2 + 1, e);
190 r->upd(x, y, val);
191 }
192 }
193 fix(y);
194 }
195
196 long long query(int i, int j, int st, int en) //gcd of a[x][y]
197 // such that i <= x <= j && st <= y <= en
198 {
199 if (e < i || j < b) return 0;
200 if (i <= b && e <= j) return t.query(st, en);
201 long long ans = 0;
202 if (l) ans = __gcd(ans, l->query(i, j, st, en));
203 if (r) ans = __gcd(ans, r->query(i, j, st, en));
204 return ans;
205 }
206 };
207
208 int r, c, q;
209 ST t;
210
211 void init(int R, int C)
212 {
213 r = R; c = C;
214 t = ST(0, r - 1);
215 }
216
217 void update(int P, int Q, long long K)
218 {
219 t.upd(P, Q, K);
220 }
221
222 long long calculate(int P, int Q, int U, int V)
223 {
224 return t.query(P, U, Q, V);
225 }
226
CAPITOLUL 8. IOI 2013 928
303
304 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
305 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
306 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
307
308 return 0;
309 }
310
311 // ------------- end grader ----------------------
312 /*
313 t2-t1 = 0
314 t3-t2 = 0
315 t4-t3 = 9.14
316
317 Process returned 0 (0x0) execution time : 9.188 s
318 Press any key to continue.
319 */
208 int P, Q, U, V;
209 long long K;
210 int i, type;
211 int res;
212
213 res = scanf("%d", &R);
214
215 if (res != 1)
216 fail("Failed to read R from input file.");
217 if (R < 1 || R > MAX_SIZE)
218 fail("R is out of bounds.");
219
220 res = scanf("%d", &C);
221
222 if (res != 1)
223 fail("Failed to read C from input file.");
224 if (C < 1 || C > MAX_SIZE)
225 fail("C is out of bounds.");
226
227 res = scanf("%d", &N);
228
229 if (res != 1)
230 fail("Failed to read N from input file.");
231 if (N < 0 || N > MAX_N)
232 fail("N is out of bounds.");
233
234 auto t2 = clock();
235
236 init(R, C);
237
238 auto t3 = clock();
239
240 for (i = 0; i < N; i++)
241 {
242 res = scanf("%d", &type);
243
244 if (type == 1)
245 {
246 res = scanf("%d%d%lld", &P, &Q, &K);
247
248 update(P, Q, K);
249 }
250 else
251 if (type == 2)
252 {
253 res = scanf("%d%d%d%d", &P, &Q, &U, &V);
254
255 printf("%lld\n", calculate(P, Q, U, V));
256 }
257 else
258 fail("Invalid action type in input file.");
259 }
260
261 auto t4 = clock();
262
263 // reset console output
264 freopen("CON", "w", stdout);
265
266 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
267 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
268 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
269
270 return 0;
271 }
272
273 // ------------- end grader ----------------------
274 /*
275 t2-t1 = 0
276 t3-t2 = 0
277 t4-t3 = 6.031
278
279 Process returned 0 (0x0) execution time : 6.078 s
280 Press any key to continue.
281 */
76 now->v = k;
77 }
78 else
79 if(now->l <= p && p <= now->r) update2(now, p, k);
80 else
81 {
82 while((p <= mid) == (now->l <= mid))
83 {
84 (p <= mid) ? r = mid : l = mid+1;
85 mid = (l+r)>>1;
86 }
87 node2 *next = new node2(l, r);
88 (now->l <= mid) ? next->L = now : next->R = now;
89 now = next;
90 update2(next, p, k);
91 }
92 seg->v = gcd2((seg->L) ? seg->L->v : 0, (seg->R) ? seg->R->v : 0);
93 }
94
95 void update1(node1 *&seg, int p, int q, long long k)
96 {
97 if(seg->l == seg->r) return void(update2(seg->now, q, k));
98 int mid = (seg->l + seg->r)>>1;
99 if(p <= mid)
100 {
101 if(!seg->L) seg->L = new node1(seg->l, mid);
102 update1(seg->L, p, q, k);
103 }
104 else
105 {
106 if(!seg->R) seg->R = new node1(mid+1, seg->r);
107 update1(seg->R, p, q, k);
108 }
109
110 long long v = gcd2((seg->L) ? query2(seg->L->now, q, q) : 0,
111 (seg->R) ? query2(seg->R->now, q, q) : 0);
112 update2(seg->now, q, v);
113 }
114
115 void init(int R, int C)
116 {
117 _R = R, _C = C;
118 root = new node1(1, _R);
119 }
120
121 void update(int P, int Q, long long K)
122 {
123 P++, Q++;
124 update1(root, P, Q, K);
125 }
126
127 long long calculate(int P, int Q, int U, int V)
128 {
129 P++, Q++, U++, V++;
130 return query1(root, P, U, Q, V);
131 }
132
133 // ------------- begin grader ----------------------
134
135 #define fail(s, x...) do { \
136 fprintf(stderr, s "\n", ## x); \
137 exit(1); \
138 } while(0)
139
140 #define MAX_SIZE 1000000000
141 //#define MAX_N 100000
142 #define MAX_N 272000
143
144 int main()
145 {
146 auto t1 = clock();
147
148 std::freopen("../tests/05.st-4-random-1.in", "r", stdin);
149 std::freopen("game.out", "w", stdout);
150
151 int R, C, N;
CAPITOLUL 8. IOI 2013 935
152 int P, Q, U, V;
153 long long K;
154 int i, type;
155 int res;
156
157 res = scanf("%d", &R);
158
159 if (res != 1)
160 fail("Failed to read R from input file.");
161 if (R < 1 || R > MAX_SIZE)
162 fail("R is out of bounds.");
163
164 res = scanf("%d", &C);
165
166 if (res != 1)
167 fail("Failed to read C from input file.");
168 if (C < 1 || C > MAX_SIZE)
169 fail("C is out of bounds.");
170
171 res = scanf("%d", &N);
172
173 if (res != 1)
174 fail("Failed to read N from input file.");
175 if (N < 0 || N > MAX_N)
176 fail("N is out of bounds.");
177
178 auto t2 = clock();
179
180 init(R, C);
181
182 auto t3 = clock();
183
184 for (i = 0; i < N; i++)
185 {
186 res = scanf("%d", &type);
187
188 if (type == 1)
189 {
190 res = scanf("%d%d%lld", &P, &Q, &K);
191
192 update(P, Q, K);
193 }
194 else
195 if (type == 2)
196 {
197 res = scanf("%d%d%d%d", &P, &Q, &U, &V);
198
199 printf("%lld\n", calculate(P, Q, U, V));
200 }
201 else
202 fail("Invalid action type in input file.");
203 }
204
205 auto t4 = clock();
206
207 // reset console output
208 freopen("CON", "w", stdout);
209
210 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
211 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
212 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
213
214 return 0;
215 }
216
217 // ------------- end grader ----------------------
218 /*
219 t2-t1 = 0
220 t3-t2 = 0
221 t4-t3 = 6.859
222
223 Process returned 0 (0x0) execution time : 6.906 s
224 Press any key to continue.
225 */
1 #include "testlib.h"
2
3 using namespace std;
4
5 int main()
6 //int main(int argc, char * argv[])
7 {
8 int argc=4;
9
10 char* argv[] =
11 {
12 (char*)"checker",
13 (char*)"../tests/05.st-4-random-1.in",
14 (char*)"game.out",
15 (char*)"../tests/05.st-4-random-1.out",
16 };
17
18 cout<<"argc = "<<argc<<"\n";
19 for(int kk=0;kk<argc;kk++)
20 cout<<argv[kk]<<"\n";
21 cout<<"----------------------\n";
22
23 registerChecker("game", argc, argv);
24 compareRemainingLines();
25 }
8.5 Robots
Problema 5 - Robots 100 de puncte
Author: Vytautas Gruslys (Lithuania)
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, ecare 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
armativ care este timpul minim in care acestea pot 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
Cel mai scurt timp pentru a culege toate juc riile este de trei minute:
CAPITOLUL 8. IOI 2013 937
Pascal
function putaway(A, B, T : LongInt;
var X, Y, W, S : array of LongInt) : LongInt;
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 ecare robot weak.
Y: Un vector de întregi de lungime B conµinând dimensiunile limit pentru ecare robot
small.
W: Un vector de întregi de lungime T conµinând greutatea ec rei juc rii.
S: Un vector de întregi de lungime T conµinând dimensiunea ec 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 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 8. IOI 2013 938
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 ³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
Dac A 0 sau B 0 linia corespunz toare(linia 2 sau linia 3) trebuie sa e goale.
Note de limbaj
C/C++ Trebuie s faceµi #include "robots.h".
Pascal Trebuie sa deniµi unit Robots. Toµi vectorii sunt indexaµi incepând 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: 3.0 secunde
Memorie: total 64 MB
CAPITOLUL 8. IOI 2013 939
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 oor 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 rst decide the actions of the weak robots, starting from the weakest. There will be some
set of toys it can handle. Since they eectively dier 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 nished, the dierence 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.
27 std::sort(X,X+A);
28 std::sort(Y,Y+B);
29 std::sort(D,D+T);
30 for(i=0;i<T;i++)
31 if((!A||D[i].first>X[A-1])&&(!B||D[i].second>Y[B-1]))
32 return -1;
33 l=1;
34 r=T;
35 while(l<r)
36 {
37 mid=(l+r)/2;
38 for(i=0;i<T;i++)V[i]=0;
39 for(i=0;i<B;i++)E[i].clear();
40 for(i=0;i<T;i++)
41 {
42 j=std::lower_bound(Y,Y+B,D[i].second)-Y;
43 if(j<B)E[j].push_back(i);
44 }
45
46 j=0;
47 for(i=B-1;i>=0;i--)
48 {
49 j+=mid;
50 if(j>2e9)j=2e9;
51 while(j>0&&E[i].size())
52 {
53 V[E[i][E[i].size()-1]]=1;
54 E[i].pop_back();
55 j--;
56 }
57 }
58
59 for(i=0;i<A;i++)R[i]=0;
60 j=0;
61 for(i=0;i<T;i++)if(!V[i])
62 {
63 while(j<A&&(X[j]<D[i].first||R[j]==mid))j++;
64 if(j<A)
65 {
66 V[i]=1;
67 R[j]++;
68 }
69 else break;
70 }
71
72 if(i==T)r=mid;
73 else l=mid+1;
74 }
75 return r;
76 }
77
78 // ---------------- begin grader ----------------
79
80 #define fail(s, x...) do { \
81 fprintf(stderr, s "\n", ## x); \
82 exit(1); \
83 } while(0)
84
85 #define MAX_A 50000
86 #define MAX_B 50000
87 #define MAX_T 1000000
88
89 static int X[MAX_A];
90 static int Y[MAX_B];
91 static int W[MAX_T];
92 static int S[MAX_T];
93
94 int main()
95 {
96 auto t1 = clock();
97
98 std::freopen("../tests/st5-random-highS-highW-clusters.in", "r", stdin);
99 std::freopen("robot.out", "w", stdout);
100
101 int A, B, T, i;
102 int res;
CAPITOLUL 8. IOI 2013 941
103
104 res = scanf("%d", &A);
105
106 if (res != 1) fail("Failed to read A from input file.");
107 if (A < 0 || A > MAX_A) fail("A is out of bounds.");
108
109 res = scanf("%d", &B);
110
111 if (res != 1) fail("Failed to read B from input file.");
112 if (B < 0 || B > MAX_B) fail("B is out of bounds.");
113
114 res = scanf("%d", &T);
115
116 if (res != 1) fail("Failed to read T from input file.");
117 if (T < 1 || T > MAX_T) fail("T is out of bounds.");
118
119 for (i = 0; i < A; i++)
120 {
121 res = scanf("%d", &X[i]);
122
123 if (res != 1) fail("Failed to read data from input file.");
124 }
125
126 for (i = 0; i < B; i++)
127 {
128 res = scanf("%d", &Y[i]);
129
130 if (res != 1) fail("Failed to read data from input file.");
131 }
132
133 for (i = 0; i < T; i++)
134 {
135 res = scanf("%d%d", &W[i], &S[i]);
136
137 if (res != 2) fail("Failed to read data from input file.");
138 }
139
140 auto t2 = clock();
141
142 int answer = putaway(A, B, T, X, Y, W, S);
143
144 auto t3 = clock();
145
146 printf("%d\n", answer);
147
148 auto t4 = clock();
149
150 // reset console output
151 freopen("CON", "w", stdout);
152
153 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
154 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
155 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
156
157 return 0;
158 }
159
160 // ---------------- end grader ----------------
161
162 /*
163 t2-t1 = 0.515
164 t3-t2 = 8.761
165 t4-t3 = 0
166
167 Process returned 0 (0x0) execution time : 9.308 s
168 Press any key to continue.
169
170 argc = 4
171 checker
172 ../tests/st5-random-highS-highW-clusters.in
173 robot.out
174 ../tests/st5-random-highS-highW-clusters.out
175 ----------------------
176 1
177 Correct
178
CAPITOLUL 8. IOI 2013 942
70 }
71 else break;
72 }
73
74 if(i==T)r=mid;
75 else l=mid+1;
76 }
77 return r;
78 }
79
80 // ---------------- begin grader ----------------
81
82 #define fail(s, x...) do { \
83 fprintf(stderr, s "\n", ## x); \
84 exit(1); \
85 } while(0)
86
87 #define MAX_A 50000
88 #define MAX_B 50000
89 #define MAX_T 1000000
90
91 static int X[MAX_A];
92 static int Y[MAX_B];
93 static int W[MAX_T];
94 static int S[MAX_T];
95
96 int main()
97 {
98 auto t1 = clock();
99
100 std::freopen("../tests/st5-random-highS-highW-clusters.in", "r", stdin);
101 std::freopen("robot.out", "w", stdout);
102
103 int A, B, T, i;
104 int res;
105
106 res = scanf("%d", &A);
107
108 if (res != 1) fail("Failed to read A from input file.");
109 if (A < 0 || A > MAX_A) fail("A is out of bounds.");
110
111 res = scanf("%d", &B);
112
113 if (res != 1) fail("Failed to read B from input file.");
114 if (B < 0 || B > MAX_B) fail("B is out of bounds.");
115
116 res = scanf("%d", &T);
117
118 if (res != 1) fail("Failed to read T from input file.");
119 if (T < 1 || T > MAX_T) fail("T is out of bounds.");
120
121 for (i = 0; i < A; i++)
122 {
123 res = scanf("%d", &X[i]);
124
125 if (res != 1) fail("Failed to read data from input file.");
126 }
127
128 for (i = 0; i < B; i++)
129 {
130 res = scanf("%d", &Y[i]);
131
132 if (res != 1) fail("Failed to read data from input file.");
133 }
134
135 for (i = 0; i < T; i++)
136 {
137 res = scanf("%d%d", &W[i], &S[i]);
138
139 if (res != 2) fail("Failed to read data from input file.");
140 }
141
142 auto t2 = clock();
143
144 int answer = putaway(A, B, T, X, Y, W, S);
145
CAPITOLUL 8. IOI 2013 944
35 bool f(int x)
36 {
37 v.clear();
38 for(int i = 0; i <= A; i++)
39 {
40 root[i] = i;
41 sizev[i] = x;
42 }
43
44 for(int i = n - 1; i >= 0; i--)
45 {
46 int go = dsu(id[i]);
47 if(go < A)
48 {
49 sizev[go]--;
50 if(!sizev[go])
51 {
52 root[go] = go + 1;
53 }
54 }
55 else
56 {
57 v.push_back(a[i].second);
58 }
59 }
60
61 int ptr = 0;
62 for(int i = B - 1; i >= 0; i--)
63 {
64 int rem = x;
65 while(ptr < v.size() and rem and Y[i] > v[ptr])
66 {
67 rem--;
68 ptr++;
69 }
70 }
71 return ptr == v.size();
72 }
73
74 int putaway(int A, int B, int n, int X[], int Y[], int W[], int S[])
75 {
76 :: n = n;
77 :: A = A;
78 :: B = B;
79
80 sort(X, X + A);
81 sort(Y, Y + B);
82
83 for(int i = 0; i < A; i++)
84 :: X[i] = X[i];
85
86 for(int i = 0; i < B; i++)
87 :: Y[i] = Y[i];
88
89 for(int i = 0; i < n; i++)
90 {
91 a[i] = ii(S[i], W[i]);
92 }
93
94 sort(a, a + n);
95
96 for(int i = 0; i < n; i++)
97 swap(a[i].first, a[i].second);
98
99 for(int i = 0; i < n; i++)
100 {
101 id[i] = upper_bound(X, X + A, a[i].first) - X;
102 }
103
104 if(!f(n))
105 return -1;
106
107 int l = 1, r = n;
108 while(l < r)
109 {
110 int m = l + r >> 1;
CAPITOLUL 8. IOI 2013 946
111 if(f(m))
112 r = m;
113 else
114 l = m + 1;
115 }
116 return l;
117 }
118
119 // ---------------- begin grader ----------------
120
121 #define fail(s, x...) do { \
122 fprintf(stderr, s "\n", ## x); \
123 exit(1); \
124 } while(0)
125
126 #define MAX_A 50000
127 #define MAX_B 50000
128 #define MAX_T 1000000
129
130 static int XX[MAX_A];
131 static int YY[MAX_B];
132 static int WW[MAX_T];
133 static int SS[MAX_T];
134
135 int main()
136 {
137 auto t1 = clock();
138
139 std::freopen("../tests/st5-random-highS-highW-clusters.in", "r", stdin);
140 std::freopen("robot.out", "w", stdout);
141
142 int A, B, T, i;
143 int res;
144
145 res = scanf("%d", &A);
146
147 if (res != 1) fail("Failed to read A from input file.");
148 if (A < 0 || A > MAX_A) fail("A is out of bounds.");
149
150 res = scanf("%d", &B);
151
152 if (res != 1) fail("Failed to read B from input file.");
153 if (B < 0 || B > MAX_B) fail("B is out of bounds.");
154
155 res = scanf("%d", &T);
156
157 if (res != 1) fail("Failed to read T from input file.");
158 if (T < 1 || T > MAX_T) fail("T is out of bounds.");
159
160 for (i = 0; i < A; i++)
161 {
162 res = scanf("%d", &XX[i]);
163
164 if (res != 1) fail("Failed to read data from input file.");
165 }
166
167 for (i = 0; i < B; i++)
168 {
169 res = scanf("%d", &YY[i]);
170
171 if (res != 1) fail("Failed to read data from input file.");
172 }
173
174 for (i = 0; i < T; i++)
175 {
176 res = scanf("%d%d", &WW[i], &SS[i]);
177
178 if (res != 2) fail("Failed to read data from input file.");
179 }
180
181 auto t2 = clock();
182
183 int answer = putaway(A, B, T, XX, YY, WW, SS);
184
185 auto t3 = clock();
186
CAPITOLUL 8. IOI 2013 947
37 }
38 else
39 {
40 int cur = w[x].first;
41 int use = 0;
42 while(use < md && i < t && cur > tw[i].first)
43 {
44 if(used[tw[i].second])
45 {
46 i++;
47 continue;
48 }
49 used[tw[i].second] = 1;
50 i++;
51 use++;
52 }
53 }
54 }
55
56 for(int x=0;x<t;x++)
57 if(!used[x])
58 return 0;
59 return 1;
60 }
61
62 int putaway(int A, int B, int T, int X[], int Y[], int W[], int S[])
63 {
64 t = T;
65 for(int i=0;i<A;i++)w.push_back({X[i],0});
66 for(int i=0;i<B;i++)w.push_back({Y[i],1});
67 for(int i=0;i<T;i++)tw.push_back({W[i],i});
68 for(int i=0;i<T;i++)ts.push_back({S[i],i});
69
70 sort(w.begin(),w.end());
71 sort(tw.begin(),tw.end());
72 sort(ts.begin(),ts.end());
73
74 int md,lo=0,hi=T,ans=-1;
75 while(lo <= hi)
76 {
77 md = (lo+hi)/2;
78 if(can(md))
79 {
80 ans = md;
81 hi = md-1;
82 }
83 else
84 lo = md+1;
85 }
86 return ans;
87 }
88
89 // ---------------- begin grader ----------------
90
91 #define fail(s, x...) do { \
92 fprintf(stderr, s "\n", ## x); \
93 exit(1); \
94 } while(0)
95
96 #define MAX_A 50000
97 #define MAX_B 50000
98 #define MAX_T 1000000
99
100 static int X[MAX_A];
101 static int Y[MAX_B];
102 static int W[MAX_T];
103 static int S[MAX_T];
104
105 int main()
106 {
107 auto t1 = clock();
108
109 std::freopen("../tests/st5-random-highS-highW-clusters.in", "r", stdin);
110 std::freopen("robot.out", "w", stdout);
111
112 int A, B, T, i;
CAPITOLUL 8. IOI 2013 949
189
190 Process returned 0 (0x0) execution time : 0.031 s
191 Press any key to continue.
192 */
69
70 sort(w.begin(),w.end());
71 sort(tw.begin(),tw.end());
72 sort(ts.begin(),ts.end());
73
74 int md,lo=0,hi=T,ans=-1;
75 while(lo <= hi)
76 {
77 md = (lo+hi)/2;
78 if(can(md))
79 {
80 ans = md;
81 hi = md-1;
82 }
83 else
84 lo = md+1;
85 }
86 return ans;
87 }
88
89 // ---------------- begin grader ----------------
90
91 #define fail(s, x...) do { \
92 fprintf(stderr, s "\n", ## x); \
93 exit(1); \
94 } while(0)
95
96 #define MAX_A 50000
97 #define MAX_B 50000
98 #define MAX_T 1000000
99
100 static int X[MAX_A];
101 static int Y[MAX_B];
102 static int W[MAX_T];
103 static int S[MAX_T];
104
105 int main()
106 {
107 auto t1 = clock();
108
109 std::freopen("../tests/st5-random-highS-highW-clusters.in", "r", stdin);
110 std::freopen("robot.out", "w", stdout);
111
112 int A, B, T, i;
113 int res;
114
115 res = scanf("%d", &A);
116
117 if (res != 1) fail("Failed to read A from input file.");
118 if (A < 0 || A > MAX_A) fail("A is out of bounds.");
119
120 res = scanf("%d", &B);
121
122 if (res != 1) fail("Failed to read B from input file.");
123 if (B < 0 || B > MAX_B) fail("B is out of bounds.");
124
125 res = scanf("%d", &T);
126
127 if (res != 1) fail("Failed to read T from input file.");
128 if (T < 1 || T > MAX_T) fail("T is out of bounds.");
129
130 for (i = 0; i < A; i++)
131 {
132 res = scanf("%d", &X[i]);
133
134 if (res != 1) fail("Failed to read data from input file.");
135 }
136
137 for (i = 0; i < B; i++)
138 {
139 res = scanf("%d", &Y[i]);
140
141 if (res != 1) fail("Failed to read data from input file.");
142 }
143
144 for (i = 0; i < T; i++)
CAPITOLUL 8. IOI 2013 952
145 {
146 res = scanf("%d%d", &W[i], &S[i]);
147
148 if (res != 2) fail("Failed to read data from input file.");
149 }
150
151 auto t2 = clock();
152
153 int answer = putaway(A, B, T, X, Y, W, S);
154
155 auto t3 = clock();
156
157 printf("%d\n", answer);
158
159 auto t4 = clock();
160
161 // reset console output
162 freopen("CON", "w", stdout);
163
164 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
165 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
166 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
167
168 return 0;
169 }
170
171 // ---------------- end grader ----------------
172
173 /*
174 t2-t1 = 2
175 t3-t2 = 2.453
176 t4-t3 = 0
177
178 Process returned 0 (0x0) execution time : 4.484 s
179 Press any key to continue.
180
181 argc = 4
182 checker
183 ../tests/st5-random-highS-highW-clusters.in
184 robot.out
185 ../tests/st5-random-highS-highW-clusters.out
186 ----------------------
187 1
188 Correct
189
190 Process returned 0 (0x0) execution time : 0.031 s
191 Press any key to continue.
192 */
8.6 Wombats
Problema 6 - Wombats 100 de puncte
Author: Richard Peng (USA)
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 gura urmatoare.
CAPITOLUL 8. IOI 2013 953
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 ecare segment de strad .
în continuare veµi primi o serie de E evenimente din unul din urm toarele dou tipuri:
change, care modic 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.
Implementare
Va trebui sa submitaµi un ³ier implementând procedurile init(), changeH() ³i changeV()
³i funcµia escape(), dup cum urmeaz :
Procedura vostr : init()
C/C++
void init(int R, int C, int H[5000][200], int V[5000][200]);
Pascal
type wombatsArrayType = array[0..4999, 0..199] of LongInt;
procedure init(R, C : LongInt; var H, V : wombatsArrayType);
Descriere
Aceast procedur v d conguraµia iniµiala a h rµii, ³i v permite s iniµializaµi eventualele
variabile globale ³i structuri de date. Va 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 apelat atunci când num rul de wombaµi se modic 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 a segmentul ( 0 ⤠Q ⤠C - 2 ).
Pascal
procedure changeV(P, Q, W: LongInt);
Descriere
Acest procedur va apelat când num rul de wombaµi se modic pe pe segmentul de drum
vertical dintre intersecµiile (P, Q) ³i (P + 1, Q).
Parametrii
CAPITOLUL 8. IOI 2013 955
P : Indic între care dou drumuri orizontale se a segmentul ( 0 ⤠P ⤠R - 2 ).
Q : Indic care drum este afectat ( 0 ⤠Q ⤠C - 1 ).
W : Num rul nou de wombaµi pe acest segment de drum ( 0 ⤠W ⤠1,000 ).
Pascal
function escape(V1, V2 : LongInt) : LongInt;
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 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 ecare 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 apeluri c tre changeH() sau changeV()
3 16 R, C & 100, ³i vor 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 ³ierul wombats.in, care va î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 8. IOI 2013 956
...
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 ec rui eveniment trebuie s e î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
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 deniµ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 dicult of the tasks. Apart from being conceptually dicult, 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 aord R
dierent rX, Y x tables. Instead of keeping rX, X 1x at the nest 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 8. IOI 2013 957
147 }
148
149 auto t4 = clock();
150
151 // reset console output
152 freopen("CON", "w", stdout);
153
154 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
155 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
156 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
157
158 return 0;
159 }
160
161 // ------------- end grader ----------------
162 /*
163 t2-t1 = 0.031
164 t3-t2 = 26.213
165 t4-t3 = 18.542
166
167 Process returned 0 (0x0) execution time : 44.841 s
168 Press any key to continue.
169 */
50 }
51 }
52 }
53
54 void init(int r, int c, int h[5000][200], int v[5000][200])
55 {
56 memset(::h, 0x3f, sizeof(::h));
57 for(int i=0; i<r; ++i)
58 for(int j=0; j<c-1; ++j)
59 ::h[i][j]=h[i][j];
60 for(int i=0; i<r-1; ++i)
61 for(int j=0; j<c; ++j)
62 ::v[i][j]=v[i][j];
63 o[::c]=::c-1;
64 upd(0, bc-1);
65 }
66
67 void changeH(int p, int q, int w)
68 {
69 h[p][q]=w;
70 upd(p/bs, p/bs);
71 }
72
73 void changeV(int p, int q, int w) {
74 v[p][q]=w;
75 upd(p/bs, p/bs);
76 }
77
78 int escape(int a, int b)
79 {
80 return st[1][a][b];
81 }
82
83 // ------------- begin grader --------------
84
85 #define fail(s, x...) do { \
86 fprintf(stderr, s "\n", ## x); \
87 exit(1); \
88 } while(0)
89
90 static int H[5000][200];
91 static int V[5000][200];
92
93 int main()
94 {
95 auto t1 = clock();
96
97 std::freopen("../tests/100x100-bottom-changes-many-queries.in", "r",stdin);
98 std::freopen("wombats.out", "w", stdout);
99
100 int R, C, E, P, Q, W, V1, V2, event, i, j;
101 int res;
102
103 res = scanf("%d%d", &R, &C);
104
105 for (i = 0; i < R; ++i)
106 for (j = 0; j < C-1; ++j)
107 res = scanf("%d", &H[i][j]);
108
109
110 for (i = 0; i < R-1; ++i)
111 for (j = 0; j < C; ++j)
112 res = scanf("%d", &V[i][j]);
113
114 auto t2 = clock();
115
116 init(R, C, H, V);
117
118 res = scanf("%d", &E);
119
120 auto t3 = clock();
121
122 for (i = 0; i < E; i++)
123 {
124 res = scanf("%d", &event);
125
CAPITOLUL 8. IOI 2013 961
126 if (event == 1)
127 {
128 res = scanf("%d%d%d", &P, &Q, &W);
129
130 changeH(P, Q, W);
131 }
132 else
133 if (event == 2)
134 {
135 res = scanf("%d%d%d", &P, &Q, &W);
136
137 changeV(P, Q, W);
138 }
139 else
140 if (event == 3)
141 {
142 res = scanf("%d%d", &V1, &V2);
143
144 printf("%d\n", escape(V1, V2));
145 }
146 else
147 fail("Invalid event type.");
148 }
149
150 auto t4 = clock();
151
152 // reset console output
153 freopen("CON", "w", stdout);
154
155 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
156 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
157 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
158
159 return 0;
160 }
161
162 // ------------- end grader ----------------
163 /*
164 t2-t1 = 0.041
165 t3-t2 = 9.078
166 t4-t3 = 8.622
167
168 Process returned 0 (0x0) execution time : 19.449 s
169 Press any key to continue.
170 */
28 }
29 return;
30 }
31
32 int m2=(l2+r2)/2;
33 if(l1<=m2)
34 upd(l1, r1, 2*i, l2, m2);
35 if(m2<r1)
36 upd(l1, r1, 2*i+1, m2+1, r2);
37 memset(o, 0, 4*c);
38 for(int j1=0; j1<c; ++j1)
39 {
40 for(int j2=c-1; ~j2; --j2)
41 {
42 array<int, 2> d{INT_MAX, 0};
43 for(int k=o[j2]; k<=o[j2+1]; ++k)
44 d=min(array<int, 2>{st[2*i][j1][k]+st[2*i+1][k][j2],-k},d);
45 st[i][j1][j2]=d[0];
46 o[j2]=-d[1];
47 }
48 }
49 }
50
51 void init(int r, int c, int h[5000][200], int v[5000][200])
52 {
53 memset(::h, 0x3f, sizeof(::h));
54 for(int i=0; i<r; ++i)
55 for(int j=0; j<c-1; ++j)
56 ::h[i][j]=h[i][j];
57 for(int i=0; i<r-1; ++i)
58 for(int j=0; j<c; ++j)
59 ::v[i][j]=v[i][j];
60 o[::c]=::c-1;
61 upd(0, bc-1);
62 }
63
64 void changeH(int p, int q, int w)
65 {
66 h[p][q]=w;
67 upd(p/bs, p/bs);
68 }
69
70 void changeV(int p, int q, int w)
71 {
72 v[p][q]=w;
73 upd(p/bs, p/bs);
74 }
75
76 int escape(int a, int b)
77 {
78 return st[1][a][b];
79 }
80
81 // ------------- begin grader --------------
82
83 #define fail(s, x...) do { \
84 fprintf(stderr, s "\n", ## x); \
85 exit(1); \
86 } while(0)
87
88 static int H[5000][200];
89 static int V[5000][200];
90
91 int main()
92 {
93 auto t1 = clock();
94
95 std::freopen("../tests/100x100-bottom-changes-many-queries.in","r",stdin);
96 std::freopen("wombats.out", "w", stdout) ;
97
98 int R, C, E, P, Q, W, V1, V2, event, i, j;
99 int res;
100
101 res = scanf("%d%d", &R, &C);
102
103 for (i = 0; i < R; ++i)
CAPITOLUL 8. IOI 2013 963
8 int argc=4;
9
10 char* argv[] =
11 {
12 (char*)"checker",
13 (char*)"../tests/100x100-bottom-changes-many-queries.in",
14 (char*)"wombats.out",
15 (char*)"../tests/100x100-bottom-changes-many-queries.out",
16 };
17
18 cout<<"argc = "<<argc<<"\n";
19 for(int kk=0;kk<argc;kk++)
20 cout<<argv[kk]<<"\n";
21 cout<<"----------------------\n";
22
23 registerChecker("wombats", argc, argv);
24 compareRemainingLines();
25 }
IOI 201234
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 aam 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 specicate 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 identic printr-o pereche de coordonate (rând, coloan ),
unde ecare coordonat se a î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 aat 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 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
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 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 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
34
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).
965
CAPITOLUL 9. IOI 2012 966
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 veric dac se a pietricele
sau dac se a 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) specic
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 e sucient 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 sucient de repede. Lungimea execuµiei
este num rul de pa³i: ecare 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 9. IOI 2012 967
submisie pentru task-ul x va 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
nal 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 scrise în formatul folosit pentru submit-uri
(de exemplu, unul din cele descrise mai sus).
Descrierea matricei va dat cu ajutorul urm torului format: ecare linie a ³ierului trebuie
s conµin trei numere R, C ³i P , semnicand faptul c celula din randul R ³i coloana C conµine
P pietricele. Se presupune c celulele ce nu sunt specicate în descrierea matriceise nu conµin
pietricele. Pentru exemplicare se consider urm torul ³ier:
0 10 3
4 5 12
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 nding 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 sosticat 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
u³or legate între ele, iar ecare inel poate închis sau deschis din nou. Numim lanµ o secvenµ
de unul sau mai multe inele legate, în care ecare 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
deniµie, un singur inel este, de asemenea, un lanµ.
CAPITOLUL 9. IOI 2012 970
Evident, întrucât un inel poate legat nu numai cu dou , dar cu trei ³i chiar mai multe inele,
sunt posibile ³i alte conguraµ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 gura 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 conguraµ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 conguraµia curent . Mai
concret, trebui s implementezii trei rutine.
Init(N) - la început aceasta se apeleaz exact o singur dat pentru a aa num rul N de
inele disjuncte din conguraµia iniµial , numerotate de la 0 la N 1 (inclusiv).
Link(A, B) - cele dou inele A ³i B vor 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 zice. Evident, apelurile
Link(A,B) ³i Link(B,A) sunt echivalente.
CountCritical() - returneaz num rul de inele critice din conguraµ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 conguraµia prezentat în gura de mai sus.
CAPITOLUL 9. IOI 2012 971
Detalii de implementare
Tu trebuie s transmiµi exact un singur ³ier, denumit rings.c, rings.cpp sau rings.pas.
Acest ³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 ³ier.
CAPITOLUL 9. IOI 2012 972
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-nd d.s., etc.).
256 int i;
257 for (i = 0; i < L; i++)
258 {
259 int A, B;
260 tmp = scanf("%d", &A);
261
262 if (A == -1)
263 {
264 int critical;
265 critical = CountCritical();
266 printf("%d\n", critical);
267 }
268 else
269 {
270 tmp = scanf("%d", &B);
271 assert(tmp == 1);
272 Link(A, B);
273 }
274 }
275
276 auto t4 = clock();
277
278 // reset console output
279 freopen("CON", "w", stdout);
280
281 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
282 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
283 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
284
285 return 0;
286
287 }
288
289 // ----------------- end grader ------------------
290 /*
291 t2-t1 = 0
292 t3-t2 = 0.016
293 t4-t3 = 3.612
294
295 Process returned 0 (0x0) execution time : 4.346 s
296 Press any key to continue.
297 */
31 if (!ck)
32 {
33 E[a][deg[0][a]] = b, E[b][deg[0][b]] = a;
34 }
35 deg[ck][a]++, deg[ck][b]++;
36 if (ck && (deg[ck][a] >= 3 || deg[ck][b] >= 3))
37 {
38 chk[ck] = 1;
39 return;
40 }
41 a = Find(ck, a), b = Find(ck, b);
42 if (a == b)
43 {
44 if (!ck)
45 {
46 cyc++;
47 if (cyc == 1)Res = SZ[a];
48 }
49 else chk[ck] = 1;
50 }
51 else
52 {
53 par[ck][a] = b;
54 if (!ck)
55 {
56 SZ[b] += SZ[a];
57 SZ[a] = 0;
58 }
59 }
60 }
61
62 void Make(int a)
63 {
64 int i, j, k, x;
65 Num[1] = a;
66 for (i = 0; i < 3; i++)
67 {
68 Num[2 + i] = E[a][i];
69 }
70 chk[0] = 1;
71 for (k = 1; k <= 4; k++)
72 {
73 for (i = 1; i <= n; i++)par[k][i] = i;
74 for (i = 1; i <= n; i++)
75 {
76 for (j = 0; j < deg[0][i]; j++){
77 x = E[i][j];
78 if (i == Num[k] || x == Num[k] || x > i)continue;
79 Add(k, i, x);
80 }
81 }
82 }
83 }
84
85 void Link(int A, int B)
86 {
87 if (!Res)return;
88 A++, B++;
89 if (!chk[0])
90 {
91 if (cyc == 2)Res = 0;
92 Add(0, A, B);
93 if (deg[0][A] == 3)
94 {
95 Make(A);
96 }
97 else
98 if (deg[0][B] == 3)
99 {
100 Make(B);
101 }
102 }
103 else
104 {
105 int i;
106 for (i = 1; i <= 4; i++)Add(i, A, B);
CAPITOLUL 9. IOI 2012 978
107 }
108 }
109
110 int CountCritical()
111 {
112 if (!chk[0])
113 {
114 if (cyc == 2)Res = 0;
115 return Res;
116 }
117 int i, r = 0;
118 for (i = 1; i <= 4; i++)if (!chk[i])r++;
119 return r;
120 }
121
122 // ----------------- begin grader ------------------
123
124 #define inbuf_len 1 << 16
125 #define outbuf_len 1 << 16
126
127 void Init(int N);
128 int CountCritical();
129 void Link(int a, int b);
130
131 int main()
132 {
133 auto t1 = clock();
134
135 std::freopen("../input/input54.txt", "r", stdin);
136 std::freopen("rings.out", "w", stdout);
137
138 int tmp;
139
140 /* Set input and output buffering */
141 char *inbuf, *outbuf;
142 inbuf = (char*) malloc(inbuf_len * sizeof(char));
143 outbuf = (char*) malloc(outbuf_len * sizeof(char));
144 tmp = setvbuf(stdin, inbuf, _IOFBF, inbuf_len);
145 tmp = setvbuf(stdout, outbuf, _IOFBF, outbuf_len);
146
147 auto t2 = clock();
148
149 int N, L;
150 tmp = scanf("%d %d", &N, &L);
151 assert(tmp == 2);
152 Init(N);
153
154 auto t3 = clock();
155
156 int i;
157 for (i = 0; i < L; i++)
158 {
159 int A, B;
160 tmp = scanf("%d", &A);
161
162 if (A == -1)
163 {
164 int critical;
165 critical = CountCritical();
166 printf("%d\n", critical);
167 }
168 else
169 {
170 tmp = scanf("%d", &B);
171 assert(tmp == 1);
172 Link(A, B);
173 }
174 }
175
176 auto t4 = clock();
177
178 // reset console output
179 freopen("CON", "w", stdout);
180
181 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
182 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
CAPITOLUL 9. IOI 2012 979
183 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
184
185 return 0;
186
187 }
188
189 // ----------------- end grader ------------------
190 /*
191 t2-t1 = 0
192 t3-t2 = 0.015
193 t4-t3 = 3.563
194
195 Process returned 0 (0x0) execution time : 3.656 s
196 Press any key to continue.
197 */
58 {
59 return (par[x]==x)?x:(par[x]=R(par[x]));
60 }
61
62 void join(int a,int b)
63 {
64 a=R(a); b=R(b);
65 if(a == b)
66 {
67 ++cyc_cnt;
68 cyc_size += sz[a];
69 }
70 else
71 {
72 sz[b] += sz[a];
73 par[a] = b;
74 }
75 }
76
77 void Init(int n_)
78 {
79 n=n_;
80 for(int i=0; i<n; ++i) par[i]=i, sz[i]=1;
81 }
82
83 int first_deg[1000010];
84 bool isSim;
85
86 simulator ss[4];
87
88 void Link(int A, int B)
89 {
90 if(!isSim)
91 {
92 ++first_deg[A]; ++first_deg[B];
93 links.push_back({A, B});
94 join(A,B);
95
96 int thr = -1;
97 if(first_deg[A] == 3) thr = A;
98 if(first_deg[B] == 3) thr = B;
99
100 if(thr != -1)
101 {
102 vector<int> inj;
103 for(pp& l:links)
104 {
105 int a,b; tie(a,b)=l;
106 if(a==thr) inj.push_back(b);
107 if(b==thr) inj.push_back(a);
108 }
109 ss[3].init(thr);
110 for(int i=0; i<3; ++i) ss[i].init(inj[i]);
111 isSim = true;
112 }
113 }
114 else
115 {
116 for(int i=0; i<4; ++i)
117 ss[i].update(A, B);
118 }
119 }
120
121 int CountCritical()
122 {
123 if(!isSim)
124 {
125 if(cyc_cnt >= 2)
126 return 0;
127 else return cyc_cnt ? cyc_size : n;
128 }
129 int ans=0;
130 for(int i=0; i<4; ++i) if(ss[i].crit) ++ans;
131 return ans;
132 }
133
CAPITOLUL 9. IOI 2012 981
75 {
76 for (j = 0; j < deg[0][i]; j++)
77 {
78 x = E[i][j];
79 if (i == Num[k] || x == Num[k] || x > i)continue;
80 Add(k, i, x);
81 }
82 }
83 }
84 }
85
86 void Link(int A, int B)
87 {
88 if (!Res)return;
89 A++, B++;
90 if (!chk[0])
91 {
92 if (cyc == 2)Res = 0;
93 Add(0, A, B);
94 if (deg[0][A] == 3)
95 {
96 Make(A);
97 }
98 else
99 if (deg[0][B] == 3)
100 {
101 Make(B);
102 }
103 }
104 else
105 {
106 int i;
107 for (i = 1; i <= 4; i++)Add(i, A, B);
108 }
109 }
110
111 int CountCritical()
112 {
113 if (!chk[0])
114 {
115 if (cyc == 2)Res = 0;
116 return Res;
117 }
118 int i, r = 0;
119 for (i = 1; i <= 4; i++)if (!chk[i])r++;
120 return r;
121 }
122
123 // ----------------- begin grader ------------------
124
125 #define inbuf_len 1 << 16
126 #define outbuf_len 1 << 16
127
128 void Init(int N);
129 int CountCritical();
130 void Link(int a, int b);
131
132 int main()
133 {
134 auto t1 = clock();
135
136 std::freopen("../input/input54.txt", "r", stdin);
137 std::freopen("rings.out", "w", stdout);
138
139 int tmp;
140
141 /* Set input and output buffering */
142 char *inbuf, *outbuf;
143 inbuf = (char*) malloc(inbuf_len * sizeof(char));
144 outbuf = (char*) malloc(outbuf_len * sizeof(char));
145 tmp = setvbuf(stdin, inbuf, _IOFBF, inbuf_len);
146 tmp = setvbuf(stdout, outbuf, _IOFBF, outbuf_len);
147
148 auto t2 = clock();
149
150 int N, L;
CAPITOLUL 9. IOI 2012 984
25 }
26
27 void join(int x, int y)
28 {
29 x = find(x), y = find(y);
30 if(x == y)
31 {
32 if(bicomp == -1) bicomp = x;
33 else bicomp = -2;
34 return;
35 }
36 if(rep[x] > rep[y]) swap(x, y);
37 rep[x] += rep[y];
38 rep[y] = x;
39 }
40
41 int max_deg = 0;
42 void add_edge(int a, int b)
43 {
44 if(a == excluded || b == excluded)
45 return;
46 max_deg = max(max_deg, ++deg[a]);
47 max_deg = max(max_deg, ++deg[b]);
48 join(a, b);
49 }
50
51 Graph(int n = 0, int e = -1) : rep(n, -1), deg(n), excluded(e) {}
52 };
53
54 int n;
55 vector<pair<int, int>> edges;
56 Graph graph;
57 vector<Graph> without;
58
59 void Init(int N)
60 {
61 n = N;
62 graph = Graph(n);
63 }
64
65 void Link(int A, int B)
66 {
67 edges.emplace_back(A, B);
68 if(graph.max_deg < 3)
69 {
70 graph.add_edge(A, B);
71 if(graph.max_deg == 3)
72 {
73 if(graph.deg[A] != 3)
74 swap(A, B);
75
76 vector<int> crit = {A};
77 for(auto &[u, v] : edges)
78 {
79 if(u == A) crit.emplace_back(v);
80 if(v == A) crit.emplace_back(u);
81 }
82
83 for(int x : crit)
84 {
85 without.emplace_back(n, x);
86 for(auto &[u, v] : edges)
87 without.back().add_edge(v, u);
88 }
89 }
90 }
91 else
92 {
93 for(auto &g : without)
94 g.add_edge(A, B);
95 }
96 }
97
98 int CountCritical()
99 {
100 if(graph.max_deg < 3)
CAPITOLUL 9. IOI 2012 986
101 {
102 if(graph.bicomp == -1) return n;
103 if(graph.bicomp == -2) return 0;
104 return graph.get_cycle();
105 }
106 else
107 {
108 int ret = 0;
109 for(auto &g : without)
110 {
111 if(g.bicomp == -1 && g.max_deg < 3)
112 ret++;
113 }
114 return ret;
115 }
116 }
117
118 // ----------------- begin grader ------------------
119
120 #define inbuf_len 1 << 16
121 #define outbuf_len 1 << 16
122
123 void Init(int N);
124 int CountCritical();
125 void Link(int a, int b);
126
127 int main()
128 {
129 auto t1 = clock();
130
131 std::freopen("../input/input54.txt", "r", stdin);
132 std::freopen("rings.out", "w", stdout);
133
134 int tmp;
135
136 /* Set input and output buffering */
137 char *inbuf, *outbuf;
138 inbuf = (char*) malloc(inbuf_len * sizeof(char));
139 outbuf = (char*) malloc(outbuf_len * sizeof(char));
140 tmp = setvbuf(stdin, inbuf, _IOFBF, inbuf_len);
141 tmp = setvbuf(stdout, outbuf, _IOFBF, outbuf_len);
142
143 auto t2 = clock();
144
145 int N, L;
146 tmp = scanf("%d %d", &N, &L);
147 assert(tmp == 2);
148 Init(N);
149
150 auto t3 = clock();
151
152 int i;
153 for (i = 0; i < L; i++)
154 {
155 int A, B;
156 tmp = scanf("%d", &A);
157
158 if (A == -1)
159 {
160 int critical;
161 critical = CountCritical();
162 printf("%d\n", critical);
163 }
164 else
165 {
166 tmp = scanf("%d", &B);
167 assert(tmp == 1);
168 Link(A, B);
169 }
170 }
171
172 auto t4 = clock();
173
174 // reset console output
175 freopen("CON", "w", stdout);
176
CAPITOLUL 9. IOI 2012 987
177 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
178 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
179 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
180
181 return 0;
182
183 }
184
185 // ----------------- end grader ------------------
186 /*
187 t2-t1 = 0
188 t3-t2 = 0.031
189 t4-t3 = 4.92
190
191 Process returned 0 (0x0) execution time : 5.014 s
192 Press any key to continue.
193 */
56 return;
57 }
58 if(lab[u] > lab[v])swap(u , v);
59 lab[u] += lab[v];
60 lab[v] = u;
61 }
62 } a[4];
63
64 void Init(int _n)
65 {
66 memset(adj,-1,sizeof adj);
67 n = _n;
68 for(int i = 0 ; i < n ; ++i)a[0].lab[i] = -1;
69 }
70
71 int cycle = 0;
72 int CurState = 0;
73
74 int dfs(int u , int b)
75 {
76 int res = 1;
77 int par = b;
78 while(u != b)
79 {
80 res++;
81 for(int i = 0 ; i < 2 ; ++i)
82 {
83 if(adj[u][i] != -1 && adj[u][i] != par)
84 {
85 par = u;u = adj[u][i];
86 break;
87 }
88 }
89 }
90 return res;
91 }
92
93 int deg[maxn];
94
95 void Link(int a , int b)
96 {
97 if(CurState == 4)return;
98 if(deg[a] < deg[b])swap(a,b);
99 deg[a]++;deg[b]++;
100 if(CurState == 3)
101 {
102 for(int i = 0 ; i < 4 ; ++i)
103 {
104 ::a[i].Connect(a,b);
105 if((a != ::a[i].banned && deg[a] - ::a[i].is_link[a] > 2) ||
106 (b != ::a[i].banned && deg[b] - ::a[i].is_link[b] > 2))
107 ::a[i].ok = 0;
108 }
109 return;
110 }
111
112 if(deg[a] == 3)
113 {
114 CurState = 3;
115 for(int i = 0 ; i < 2 ; ++i)
116 {
117 ::a[i].init(adj[a][i]);
118 }
119 ::a[2].init(b);
120 ::a[3].init(a);
121 for(int i = 0 ; i < 4 ; ++i)
122 {
123 ::a[i].Connect(a,b);
124 if((a != ::a[i].banned && deg[a] - ::a[i].is_link[a] > 2) ||
125 (b != ::a[i].banned && deg[b] - ::a[i].is_link[b] > 2))
126 {
127 ::a[i].ok = 0;
128 }
129 }
130 return;
131 }
CAPITOLUL 9. IOI 2012 989
132
133 for(int i = 0 ; i < 2 ; ++i)
134 {
135 if(adj[a][i] == -1)
136 {
137 adj[a][i] = b;
138 break;
139 }
140 }
141
142 for(int i = 0 ; i < 2 ; ++i)
143 {
144 if(adj[b][i] == -1)
145 {
146 adj[b][i] = a;
147 break;
148 }
149 }
150
151 if(::a[0].FindLab(a) == ::a[0].FindLab(b))
152 {
153 if(CurState == 2)CurState = 4;
154 else cycle = dfs(a , b) , CurState = 2;
155 }
156 else
157 {
158 ::a[0].Connect(a , b);
159 }
160 }
161
162 int CountCritical()
163 {
164 if(CurState == 4)return 0;
165 if(CurState == 3)
166 {
167 int res = 0;
168 for(int i = 0 ; i < 4 ; ++i)
169 {
170 res += a[i].ok;
171 }
172 if(res == 0)CurState = 4;
173 return res;
174 }
175
176 if(CurState == 2)return cycle;
177 return n;
178 }
179
180 // ----------------- begin grader ------------------
181
182 #define inbuf_len 1 << 16
183 #define outbuf_len 1 << 16
184
185 void Init(int N);
186 int CountCritical();
187 void Link(int a, int b);
188
189 int main()
190 {
191 auto t1 = clock();
192
193 std::freopen("../input/input54.txt", "r", stdin);
194 std::freopen("rings.out", "w", stdout);
195
196 int tmp;
197
198 /* Set input and output buffering */
199 char *inbuf, *outbuf;
200 inbuf = (char*) malloc(inbuf_len * sizeof(char));
201 outbuf = (char*) malloc(outbuf_len * sizeof(char));
202 tmp = setvbuf(stdin, inbuf, _IOFBF, inbuf_len);
203 tmp = setvbuf(stdout, outbuf, _IOFBF, outbuf_len);
204
205 auto t2 = clock();
206
207 int N, L;
CAPITOLUL 9. IOI 2012 990
25 }
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 anulat.
Detalii de implementare
Trebuie s trimiµi exact un ³ier, numit scrivener.c, scrivener.cpp sau
scrivener.pas. Acest ³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 ³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 ecare 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.
Modelul de evaluator va scrie caracterele returnate de GetLetter, ecare pe câte o linie.
Timp maxim de executare/test: *.* secunde
Memorie: total *** MB
CAPITOLUL 9. IOI 2012 993
A clever way to get an ecient 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 nal one, after processing all the commands, the nal 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 denitely more sophisticated approach to nd a point in the text. For
this it is sucient 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.
42 parents[0] = NULL;
43 }
44 else
45 {
46 depth=parent->depth+1;
47 parents = new node*[LOGMAXC];
48 parents[0] = parent;
49 for(int i=1, j=2; j<=depth+1; i++, j*=2)
50 {
51 parents[i] = parents[i-1]->parents[i-1];
52 }
53 }
54 };
55 };
56
57 node** command_base;
58 int n_commands;
59 node* current_position;
60 node* tree_root;
61
62 void Init()
63 {
64 command_base = new node*[MAXC];
65 n_commands = 0;
66 current_position = tree_root = new node(’\0’,NULL);
67 }
68
69 void TypeLetter(char L)
70 {
71 command_base[n_commands] = current_position;
72 n_commands++;
73 node* n = new node(L, current_position);
74 current_position = n;
75 }
76
77 void UndoCommands(int U)
78 {
79 node *n = command_base[n_commands - U];
80 command_base[n_commands] = current_position;
81 n_commands++;
82 current_position = n;
83 }
84
85 char GetLetter(int P)
86 {
87 node* n = current_position;
88 int distance = current_position->depth - P;
89
90 for(int shift = LOGMAXC; shift >= 0; shift--)
91 {
92 if((distance >> shift)%2 == 1)
93 n = n->parents[shift];
94 }
95
96 return n->l;
97 }
98
99 // ------------------ begin grader ----------------
100
101 int main()
102 {
103 auto t1 = clock();
104
105 std::freopen("../input/input49.txt", "r", stdin);
106 std::freopen("scrivener.out", "w", stdout);
107
108 int tmp;
109
110 /* Set input and output buffering */
111 char *inbuf, *outbuf;
112 inbuf = (char*) malloc(inbuf_len * sizeof(char));
113 outbuf = (char*) malloc(outbuf_len * sizeof(char));
114 tmp = setvbuf(stdin, inbuf, _IOFBF, inbuf_len);
115 tmp = setvbuf(stdout, outbuf, _IOFBF, outbuf_len);
116
117 Init();
CAPITOLUL 9. IOI 2012 995
118
119 auto t2 = clock();
120
121 int cmd_num;
122 tmp = scanf("%d", &cmd_num);
123 assert(tmp == 1);
124
125 auto t3 = clock();
126
127 int i;
128 for (i = 0; i < cmd_num; i++)
129 {
130 char cmd;
131 tmp = scanf(" %c", &cmd);
132 assert(tmp == 1);
133 if (cmd == ’T’)
134 {
135 char letter;
136 tmp = scanf(" %c", &letter);
137 assert(tmp == 1);
138 TypeLetter(letter);
139 }
140 else
141 if (cmd == ’U’)
142 {
143 int number;
144 tmp = scanf("%d", &number);
145 assert(tmp == 1);
146 UndoCommands(number);
147 }
148 else
149 if (cmd == ’P’)
150 {
151 int index;
152 char letter;
153 tmp = scanf("%d", &index);
154 assert(tmp == 1);
155 letter = GetLetter(index);
156 printf("%c\n", letter);
157 }
158 }
159
160 auto t4 = clock();
161
162 // reset console output
163 freopen("CON", "w", stdout);
164
165 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
166 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
167 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
168
169 return 0;
170
171 }
172 // ------------------ end grader ----------------
173 /*
174 t2-t1 = 0.015
175 t3-t2 = 0
176 t4-t3 = 2.313
177
178 Process returned 0 (0x0) execution time : 2.391 s
179 Press any key to continue.
180
181 argc = 4
182 checker
183 ../input/input49.txt
184 scrivener.out
185 ../output/output49.txt
186 ----------------------
187 1
188 Correct
189
190 Process returned 0 (0x0) execution time : 0.078 s
191 Press any key to continue.
192 */
CAPITOLUL 9. IOI 2012 996
5 #include <assert.h>
6
7 #include<ctime>
8 #include<iostream>
9
10 using namespace std;
11
12 #define inbuf_len 1 << 16
13 #define outbuf_len 1 << 16
14
15 void Init();
16 void TypeLetter(char L);
17 void UndoCommands(int U);
18 char GetLetter(int P);
19
20 int go[1000005],len[1000005],t=1,par[1000005][20];
21 char al[1000005];
22
23 void Init(){}
24
25 void TypeLetter(char L)
26 {
27 al[t]=L;
28 len[t]=len[go[t-1]]+1;
29 par[t][0]=go[t-1];
30 int u=1;
31 while(1)
32 {
33 if(len[t]>=(1<<u))
34 {
35 par[t][u]=par[par[t][u-1]][u-1];
36 u++;
37 }
38 else break;
39 }
40
41 go[t]=t;
42 t++;
43 }
44
45 void UndoCommands(int U)
46 {
47 go[t]=go[t-U-1];
48 t++;
49 }
50
51 char GetLetter(int P)
52 {
53 int o=len[go[t-1]];
54 o=o-P-1;
55 if(o==0)return al[go[t-1]];
56 int u=0,h=go[t-1];
57 while(o)
58 {
59 if(o%2)
60 {
61 h=par[h][u];
62 }
63 o/=2;
64 u++;
65 }
66
67 return al[h];
68 }
69
70 // ------------------ begin grader ----------------
71
72 int main()
73 {
74 auto t1 = clock();
75
76 std::freopen("../input/input49.txt", "r", stdin);
77 std::freopen("scrivener.out", "w", stdout);
78
79 int tmp;
80
CAPITOLUL 9. IOI 2012 999
2
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <assert.h>
6
7 #include<ctime>
8 #include<iostream>
9
10 using namespace std;
11
12 #define inbuf_len 1 << 16
13 #define outbuf_len 1 << 16
14
15 void Init();
16 void TypeLetter(char L);
17 void UndoCommands(int U);
18 char GetLetter(int P);
19
20
21 int cnt, cnt2, par[20][1000001], A[1000001], dep[1000001];
22 char S[1000001];
23
24 void Init() { }
25
26 void TypeLetter(char L)
27 {
28 ++cnt2;
29 S[cnt2] = L;
30 dep[cnt2] = dep[A[cnt]] + 1;
31 par[0][cnt2] = A[cnt];
32 for (int i = 1; i < 20; ++i)
33 par[i][cnt2] = par[i - 1][par[i - 1][cnt2]];
34 ++cnt;
35 A[cnt] = cnt2;
36 }
37
38 void UndoCommands(int U)
39 {
40 int x = cnt - U;
41 ++cnt;
42 A[cnt] = A[x];
43 }
44
45 char GetLetter(int P)
46 {
47 int x = A[cnt];
48 for (int i = 0; i < 20; ++i)
49 if (((dep[x] - P - 1) >> i) & 1)
50 {
51 x = par[i][x];
52 }
53 return S[x];
54 }
55
56 // ------------------ begin grader ----------------
57
58 int main()
59 {
60 auto t1 = clock();
61
62 std::freopen("../input/input49.txt", "r", stdin);
63 std::freopen("scrivener.out", "w", stdout);
64
65 int tmp;
66
67 /* Set input and output buffering */
68 char *inbuf, *outbuf;
69 inbuf = (char*) malloc(inbuf_len * sizeof(char));
70 outbuf = (char*) malloc(outbuf_len * sizeof(char));
71 tmp = setvbuf(stdin, inbuf, _IOFBF, inbuf_len);
72 tmp = setvbuf(stdout, outbuf, _IOFBF, outbuf_len);
73
74 Init();
75
76 auto t2 = clock();
77
CAPITOLUL 9. IOI 2012 1001
78 int cmd_num;
79 tmp = scanf("%d", &cmd_num);
80 assert(tmp == 1);
81
82 auto t3 = clock();
83
84 int i;
85 for (i = 0; i < cmd_num; i++)
86 {
87 char cmd;
88 tmp = scanf(" %c", &cmd);
89 assert(tmp == 1);
90 if (cmd == ’T’)
91 {
92 char letter;
93 tmp = scanf(" %c", &letter);
94 assert(tmp == 1);
95 TypeLetter(letter);
96 }
97 else
98 if (cmd == ’U’)
99 {
100 int number;
101 tmp = scanf("%d", &number);
102 assert(tmp == 1);
103 UndoCommands(number);
104 }
105 else
106 if (cmd == ’P’)
107 {
108 int index;
109 char letter;
110 tmp = scanf("%d", &index);
111 assert(tmp == 1);
112 letter = GetLetter(index);
113 printf("%c\n", letter);
114 }
115 }
116
117 auto t4 = clock();
118
119 // reset console output
120 freopen("CON", "w", stdout);
121
122 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
123 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
124 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
125
126 return 0;
127
128 }
129 // ------------------ end grader ----------------
130 /*
131 t2-t1 = 0
132 t3-t2 = 0
133 t4-t3 = 2.359
134
135 Process returned 0 (0x0) execution time : 2.500 s
136 Press any key to continue.
137 */
13 (char*)"../input/input49.txt",
14 (char*)"scrivener.out",
15 (char*)"../output/output49.txt",
16 };
17
18 cout<<"argc = "<<argc<<"\n";
19 for(int kk=0;kk<argc;kk++)
20 cout<<argv[kk]<<"\n";
21 cout<<"----------------------\n";
22
23 registerChecker("scrivener", argc, argv);
24 compareRemainingLines();
25 }
Leonardo, ca mulµi alµi oameni de ³tiinµ ³i arti³ti italieni de vârsta lui, era foarte interesat
de planicarea 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 innit de form p trat format din celule.
Fiecare celul se identic 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 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 conguraµ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 9. IOI 2012 1003
Când travers m ora³ul, o s ritur înseamn trecerea de la un bloc la un alt bloc adiacent.
Celulele neacoperite nu pot traversate. Fie v 0, v1 , ..., vN 1 coordonatele a N blocuri plasate
pe grid. Pentru oricare dou blocuri distincte aate 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
Conguraµ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 a la coordonatele X i, Y i cu 0 & i & N 1, ³i 1 & X i, Y i & 2 2.
31
Deoarece rezultatul poate prea mare pentru a 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 ³ier, numit city.c, city.cpp sau city.pas. Acest ³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 ³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 ecient 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 i 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.
5 */
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <assert.h>
10
11 #include<ctime>
12
13 #define inbuf_len 1 << 16
14 #define outbuf_len 1 << 16
15
16 int DistanceSum(int N, int *X, int *Y);
17
18 #include <cstdio>
19 #include <iostream>
20 #include <algorithm>
21 #include <vector>
22
23 using namespace std;
24
25 struct Point
26 {
27 int x;
28 int y;
29
30 Point() {}
31
32 Point(int _x, int _y)
33 {
34 x = _x;
35 y = _y;
36 }
37 };
38
39 bool operator< (const Point &a, const Point &b)
40 {
41 if ( a.x != b.x ) return ( a.x < b.x );
42 return ( a.y < b.y );
43 }
44
45 int const MAXN = 1000005;
46
47 int n;
48 Point squares[MAXN];
49
50 void read(int N, int *X, int *Y)
51 {
52 n = N;
53
54 for (int i=0; i<n; ++i)
55 {
56 squares[i] = Point(X[i], Y[i]);
57 }
58
59 }
60
61 void exchange()
62 { // Exchanges the x and y coordinates of all the points.
63 for (int i=0; i<n; ++i)
64 {
65 squares[i] = Point( squares[i].y, squares[i].x );
66 }
67 }
68
69 struct Node
70 {
71 int x;
72 int ymin;
73 int ymax;
74 vector<int> neighbours;
75
76 Node () {}
77
78 Node (int _x, int _ymin, int _ymax)
79 {
80 x = _x;
CAPITOLUL 9. IOI 2012 1006
81 ymin = _ymin;
82 ymax = _ymax;
83 }
84 };
85
86 vector<Node> nodes;
87
88 void make_tree()
89 { // Builds the tree of vertically/horizontally-collapsed nodes
90
91 sort( squares, squares + n );
92 nodes.clear();
93
94 // Create nodes
95
96 int cont = 0;
97 while ( cont < n )
98 {
99 int x = squares[cont].x;
100 int ymin = squares[cont].y;
101
102 int y = ymin;
103
104 int i;
105 for (i=cont+1; i<n; ++i)
106 {
107 if ( squares[i].y == y+1 ) y++;
108 else break;
109 }
110
111 int ymax = y;
112 cont = i;
113
114 nodes.push_back( Node( x, ymin, ymax ) );
115 }
116
117 // Create edges
118
119 int cont1,cont2;
120
121 cont1 = 0;
122 for ( cont2 = 1; cont2 < nodes.size(); cont2++ )
123 {
124 while ( ( nodes[cont1].x + 1 < nodes[cont2].x ) ||
125 ( nodes[cont1].x + 1 == nodes[cont2].x &&
126 nodes[cont1].ymax < nodes[cont2].ymin ) )
127 cont1++;
128
129 int numedges = 0;
130 while ( nodes[cont1].x + 1 == nodes[cont2].x &&
131 nodes[cont1].ymin <= nodes[cont2].ymax )
132 {
133 numedges++;
134 nodes[cont1].neighbours.push_back(cont2);
135 nodes[cont2].neighbours.push_back(cont1);
136 cont1++;
137 }
138
139 if ( numedges > 0 ) cont1--;
140 }
141
142 }
143
144 int weight (int i)
145 {
146 return nodes[i].ymax - nodes[i].ymin + 1;
147 }
148
149 bool visited[MAXN];
150 long long int s; // sum of all weights
151 long long int tot; // required total
152 long long int const MOD = 1000000000;
153
154 long long int dfs (int k)
155 {
156 if ( visited[k] ) return 0;
CAPITOLUL 9. IOI 2012 1007
157
158 visited[k] = 1;
159
160 long long int w = weight(k);
161 for (int i=0; i<nodes[k].neighbours.size(); ++i)
162 {
163 w += dfs( nodes[k].neighbours[i] );
164 w %= MOD;
165 }
166
167 tot += w * (s - w);
168 tot %= MOD;
169
170 return w;
171 }
172
173 long long int sum ()
174 {
175 make_tree();
176
177 s = 0;
178 tot = 0;
179 for (int i=0; i<nodes.size(); ++i)
180 {
181 s += weight(i);
182 s %= MOD;
183 visited[i] = 0;
184 }
185
186 dfs(0);
187
188 return tot;
189 }
190
191 int DistanceSum(int N, int *X, int *Y)
192 {
193 read(N, X, Y);
194
195 // Find the horizontal sum
196 long long int first = sum();
197
198 exchange();
199
200 // Find the vertical sum
201 long long int second = sum();
202
203 long long int sol = first + second;
204 sol %= MOD;
205
206 return sol;
207 }
208
209 // --------------- begin grader --------------
210
211 int main()
212 {
213 auto t1 = clock();
214
215 std::freopen("../input/input40.txt", "r", stdin);
216 std::freopen("city.out", "w", stdout);
217
218 int tmp;
219
220 /* Set input and output buffering */
221 char *inbuf, *outbuf;
222
223 inbuf = (char*) malloc(inbuf_len * sizeof(char));
224 outbuf = (char*) malloc(outbuf_len * sizeof(char));
225
226 tmp = setvbuf(stdin, inbuf, _IOFBF, inbuf_len);
227 assert(tmp == 0);
228
229 tmp = setvbuf(stdout, outbuf, _IOFBF, outbuf_len);
230 assert(tmp == 0);
231
232 int N, i;
CAPITOLUL 9. IOI 2012 1008
30
31 mat path;
32 int n;
33 int cnt[100000];
34
35 ll dfs(int v,int p,ll &ans)
36 {
37 ll ret=0;
38 for(int i=0;i<path[v].size();i++)
39 {
40 int u=path[v][i];
41 if(u==p)continue;
42 ret+=dfs(u,v,ans);
43 }
44 ret+=cnt[v];
45 ans+=(n-ret)*ret;
46 ans%=MOD;
47 return ret;
48 }
49
50 int f(int N, int *X, int *Y)
51 {
52 n=N;
53 for(int i=0;i<N;i++) s[i]=pt(X[i],Y[i]);
54 sort(s,s+N);
55 int sz=0;
56 for(int i=0;i<N;i++)
57 {
58 int p=i;
59 while(s[i].x==s[i+1].x)i++;
60 int v=p;
61 while(v<=i)
62 {
63 while(v<i&&s[v].y+1==s[v+1].y)
64 {
65 s[v].v=sz;
66 v++;
67 }
68 s[v].v=sz;
69 cnt[sz++]=s[v].y-s[p].y+1;
70 p=++v;
71 }
72 }
73
74 path.clear();
75 path.assign(sz,vec());
76
77 for(int i=0;i<N;i++)
78 {
79 pt* it=lower_bound(s,s+N,pt(s[i].x-1,s[i].y));
80 if(it->x==s[i].x-1&&it->y==s[i].y) path[s[i].v].pb(it->v);
81 it=lower_bound(s,s+N,pt(s[i].x+1,s[i].y));
82 if(it->x==s[i].x+1&&it->y==s[i].y) path[s[i].v].pb(it->v);
83 }
84
85 for(int i=0;i<sz;i++)
86 {
87 sort(path[i].begin(),path[i].end());
88 path[i].erase(unique(path[i].begin(),path[i].end()),path[i].end());
89 }
90
91 ll ret=0;
92 dfs(0,0,ret);
93 return (int)ret;
94 }
95
96 int DistanceSum(int N, int *X, int *Y)
97 {
98 return (f(N,X,Y)+f(N,Y,X))%MOD;
99 }
100
101 // --------------- begin grader --------------
102
103 int main()
104 {
105 auto t1 = clock();
CAPITOLUL 9. IOI 2012 1010
106
107 std::freopen("../input/input40.txt", "r", stdin);
108 std::freopen("city.out", "w", stdout);
109
110 int tmp;
111
112 /* Set input and output buffering */
113 char *inbuf, *outbuf;
114
115 inbuf = (char*) malloc(inbuf_len * sizeof(char));
116 outbuf = (char*) malloc(outbuf_len * sizeof(char));
117
118 tmp = setvbuf(stdin, inbuf, _IOFBF, inbuf_len);
119 assert(tmp == 0);
120
121 tmp = setvbuf(stdout, outbuf, _IOFBF, outbuf_len);
122 assert(tmp == 0);
123
124 int N, i;
125 tmp = scanf("%d", &N);
126 assert(tmp == 1);
127
128 int *sq_x, *sq_y;
129 sq_x = (int*) malloc(N * sizeof(int));
130 sq_y = (int*) malloc(N * sizeof(int));
131
132 for (i = 0; i < N; i++)
133 {
134 tmp = scanf("%d %d", &sq_x[i], &sq_y[i]);
135 assert(tmp == 2);
136 }
137
138 auto t2 = clock();
139
140 int ds = DistanceSum(N, sq_x, sq_y);
141
142 auto t3 = clock();
143
144 printf("%d\n", ds);
145
146 auto t4 = clock();
147
148 // reset console output
149 freopen("CON", "w", stdout);
150
151 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
152 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
153 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
154
155 return 0;
156
157 }
158
159 // --------------- begin grader --------------
160 /*
161 t2-t1 = 0.266
162 t3-t2 = 0.703
163 t4-t3 = 0
164
165 Process returned 0 (0x0) execution time : 1.016 s
166 Press any key to continue.
167 */
11
12 #define inbuf_len 1 << 16
13 #define outbuf_len 1 << 16
14
15 int DistanceSum(int N, int *X, int *Y);
16
17 #include<cstdio>
18 #include<algorithm>
19 #include<vector>
20
21 int a,xx,yy,i,j,p,q,back,t,x[100002],y[100002];
22 long long sum,mod=1e9,sz[100002];
23 std::vector<int>G[100002],E[100002];
24
25 struct A
26 {
27 int num,s,e;
28 };
29
30 std::vector<A>T[100002];
31
32 void dfs(int r,int par)
33 {
34 for(int k=0;k<E[r].size();k++)
35 {
36 if(par==E[r][k])continue;
37 dfs(E[r][k],r);
38 sz[r]+=sz[E[r][k]];
39 }
40 sum+=sz[r]*(long long)(a-sz[r]);
41 }
42
43 void f()
44 {
45 t=0;
46 for(i=0;i<=a;i++)
47 G[i].clear(),T[i].clear(),E[i].clear();
48
49 for(i=1;i<=a;i++)
50 {
51 G[x[i]].push_back(y[i]);
52 }
53
54 for(i=0;G[i].size();i++)
55 std::sort(G[i].begin(),G[i].end());
56
57 for(i=0;G[i].size();i++)
58 {
59 back=G[i][0];
60 for(j=0;j<G[i].size();j++)
61 {
62 if(j==G[i].size()-1||G[i][j]+1!=G[i][j+1])
63 {
64 T[i].push_back({t++,back,G[i][j]});
65 sz[t-1]=G[i][j]-back+1;
66 if(j!=G[i].size()-1)back=G[i][j+1];
67 }
68 }
69 }
70
71 for(i=1;T[i].size();i++)
72 {
73 p=0;q=0;
74 while(p<T[i-1].size()&&q<T[i].size())
75 {
76 if(T[i-1][p].e<T[i][q].s||T[i][q].e<T[i-1][p].s)
77 {
78
79 }
80 else
81 {
82 E[T[i-1][p].num].push_back(T[i][q].num);
83 E[T[i][q].num].push_back(T[i-1][p].num);
84 }
85
86 if(T[i-1][p].e<T[i][q].e) p++;
CAPITOLUL 9. IOI 2012 1012
87 else q++;
88 }
89 }
90
91 dfs(0,-1);
92 }
93
94 int DistanceSum (int N, int *X, int *Y)
95 {
96 a=N;
97 xx=2147483647;yy=2147483647;
98 for(i=1;i<=a;i++)
99 x[i]=X[i-1],y[i]=Y[i-1];
100 for(i=1;i<=a;i++)
101 xx=std::min(xx,x[i]),yy=std::min(yy,y[i]);
102 for(i=1;i<=a;i++)
103 x[i]-=xx,y[i]-=yy;
104 f();
105 for(i=1;i<=a;i++)
106 t=x[i],x[i]=y[i],y[i]=t;
107 f();
108 return sum%mod;
109 }
110
111 // --------------- begin grader --------------
112
113 int main()
114 {
115 auto t1 = clock();
116
117 std::freopen("../input/input40.txt", "r", stdin);
118 std::freopen("city.out", "w", stdout);
119
120 int tmp;
121
122 /* Set input and output buffering */
123 char *inbuf, *outbuf;
124
125 inbuf = (char*) malloc(inbuf_len * sizeof(char));
126 outbuf = (char*) malloc(outbuf_len * sizeof(char));
127
128 tmp = setvbuf(stdin, inbuf, _IOFBF, inbuf_len);
129 assert(tmp == 0);
130
131 tmp = setvbuf(stdout, outbuf, _IOFBF, outbuf_len);
132 assert(tmp == 0);
133
134 int N, i;
135 tmp = scanf("%d", &N);
136 assert(tmp == 1);
137
138 int *sq_x, *sq_y;
139 sq_x = (int*) malloc(N * sizeof(int));
140 sq_y = (int*) malloc(N * sizeof(int));
141
142 for (i = 0; i < N; i++)
143 {
144 tmp = scanf("%d %d", &sq_x[i], &sq_y[i]);
145 assert(tmp == 2);
146 }
147
148 auto t2 = clock();
149
150 int ds = DistanceSum(N, sq_x, sq_y);
151
152 auto t3 = clock();
153
154 printf("%d\n", ds);
155
156 auto t4 = clock();
157
158 // reset console output
159 freopen("CON", "w", stdout);
160
161 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
162 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
CAPITOLUL 9. IOI 2012 1013
163 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
164
165 return 0;
166
167 }
168
169 // --------------- begin grader --------------
170 /*
171 t2-t1 = 0.11
172 t3-t2 = 0.156
173 t4-t3 = 0
174
175 Process returned 0 (0x0) execution time : 0.344 s
176 Press any key to continue.
177 */
17
18 using namespace std;
19
20 vector<int>E[101000];
21 int n, SZ[101000], P[101000];
22 long long Res, D[101000], C[101000];
23
24 struct point
25 {
26 int x, y, num;
27 bool operator < (const point &p) const
28 {
29 return x != p.x ? x < p.x : y < p.y;
30 }
31 } w[101000], w2[101000], L[101000];
32
33 void DFS(int a, int pp)
34 {
35 int i;
36 C[a] = SZ[a];
37 for (i = 0; i < E[a].size(); i++)
38 {
39 if (E[a][i] != pp)
40 {
41 DFS(E[a][i], a);
42 C[a] += C[E[a][i]];
43 }
44 }
45
46 Res += C[a] * (n-C[a]);
47 }
48
49 void Do()
50 {
51 int i, cnt = 0, a, b, j, cc = 0;
52 sort(w, w + n);
53 for (i = 0; i < n; i++)
54 {
55 if (!i || w[i].x != w[i - 1].x || w[i - 1].y + 1 != w[i].y)
56 SZ[++cnt] = 0;
57 SZ[cnt]++;
58 w2[i].num = cnt, w2[i].x = w[i].y, w2[i].y = w[i].x;
59 }
60
61 for (i = 1; i <= cnt; i++)P[i] = 0;
62 sort(w2, w2 + n);
63 for (i = 0; i < n - 1; i++)
64 {
65 if (w2[i].x == w2[i + 1].x && w2[i].y + 1 == w2[i + 1].y)
66 {
67 a = w2[i].num, b = w2[i + 1].num;
68 if (P[a] != b)
69 {
70 P[a] = b;
71 L[cc].x = a, L[cc].y = b; cc++;
72 }
73 }
74 }
75
76 for (i = 0; i < cc; i++)
77 {
78 E[L[i].x].push_back(L[i].y);
79 E[L[i].y].push_back(L[i].x);
80 }
81
82 DFS(1, 0);
83 for (i = 1; i <= cnt; i++)E[i].clear();
84 }
85
86 int DistanceSum(int N, int *X, int *Y)
87 {
88 int i;
89 n = N;
90 for (i = 0; i < N; i++)
91 {
92 w[i].x = X[i], w[i].y = Y[i];
CAPITOLUL 9. IOI 2012 1017
93 }
94
95 Do();
96 for (i = 0; i < N; i++)
97 {
98 w[i].x = Y[i], w[i].y = X[i];
99 }
100
101 Do();
102 return Res%1000000000;
103 }
104
105 // --------------- begin grader --------------
106
107 int main()
108 {
109 auto t1 = clock();
110
111 std::freopen("../input/input40.txt", "r", stdin);
112 std::freopen("city.out", "w", stdout);
113
114 int tmp;
115
116 /* Set input and output buffering */
117 char *inbuf, *outbuf;
118
119 inbuf = (char*) malloc(inbuf_len * sizeof(char));
120 outbuf = (char*) malloc(outbuf_len * sizeof(char));
121
122 tmp = setvbuf(stdin, inbuf, _IOFBF, inbuf_len);
123 assert(tmp == 0);
124
125 tmp = setvbuf(stdout, outbuf, _IOFBF, outbuf_len);
126 assert(tmp == 0);
127
128 int N, i;
129 tmp = scanf("%d", &N);
130 assert(tmp == 1);
131
132 int *sq_x, *sq_y;
133 sq_x = (int*) malloc(N * sizeof(int));
134 sq_y = (int*) malloc(N * sizeof(int));
135
136 for (i = 0; i < N; i++)
137 {
138 tmp = scanf("%d %d", &sq_x[i], &sq_y[i]);
139 assert(tmp == 2);
140 }
141
142 auto t2 = clock();
143
144 int ds = DistanceSum(N, sq_x, sq_y);
145
146 auto t3 = clock();
147
148 printf("%d\n", ds);
149
150 auto t4 = clock();
151
152 // reset console output
153 freopen("CON", "w", stdout);
154
155 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
156 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
157 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
158
159 return 0;
160
161 }
162
163 // --------------- begin grader --------------
164 /*
165 t2-t1 = 0.063
166 t3-t2 = 0.312
167 t4-t3 = 0
168
CAPITOLUL 9. IOI 2012 1018
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
"online" (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 simplicat. Presupunem c exist N culori numerotate de la 0
la N 1, ³i în ecare 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, ecare
î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 9. IOI 2012 1019
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 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 ecare 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 niciodat necesar în viitor, asistentul
trebuie s elimine o astfel de culoare de pe schel .
Altfel, culoarea eliminat de pe schel trebuie s e aceea care va 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 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 a deja pe schel , deci asistentul se poate odihni.
Pentru a treia cerere (culoarea 3), asistentul scoate culoarea 0, schimbând schela în congu-
raµia [3, 2].
În nal, a patra cerere (culoarea 0) trebuie s e 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 eliminat culoarea 2 la pasul 3, deci asistentul s-ar putut odihni din
nou în pasul nal.
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 s examineze starea schelei
dup ecare cerere. De exemplu, când folose³te strategia (neoptim ) dat în exemplul 1, secvenµa
st rilor schelei ar [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 sucienµ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 decodica aceast secvenµ ajut toare ³i o poate utiliza în
alegerile sale.
CAPITOLUL 9. IOI 2012 1020
(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
executate pe rând, f r ca acestea s poat comunica între ele în timpul execuµiei.
Primul program va 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 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 ecare element curent trebuie s e procesat
înainte de a 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 (ecare
î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 ecare 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 timpul execuµiei rutina Assist trebuie s apeleze GetRequest de exact N ori, de ecare
dat primind una din cele N cereri ale lui Leonardo, în ordine. Dup ecare apel GetRequest,
dac culoarea returnat nu se a pe schel , trebuie apelat PutBack(T) cu T ales de tine. Dac
culoarea se a 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 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 e 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), Wri-
teAdvice(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 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 9. IOI 2012 1021
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 ³iere în acela³i limbaj de programare.
Primul ³ier trebuie numit advisor.c, advisor.cpp sau advisor.pas. Acest ³ier tre-
buie s implementeze rutina ComputeAdvice dup cum a fost descris mai sus ³i trebuie s
apeleze WriteAdvice. Al doilea ³ier trebuie numit assistant.c, assistant.cpp sau
assistant.pas. Acest ³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++
void ComputeAdvice(int *C, int N, int K, int M);
void WriteAdvice(unsigned char a);
void Assist(unsigned char *A, int N, int K, int R);
void PutBack(int T);
int GetRequest();
Programe Pascal
procedure ComputeAdvice(var C : array of LongInt; N, K, M : LongInt);
procedure WriteAdvice(a : Byte);
procedure Assist(var A : array of Byte; N, K, R : LongInt);
procedure PutBack(T : LongInt);
CAPITOLUL 9. IOI 2012 1022
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
ecare program) cu acela³i nume. Submisiile voastre nu au voie s interacµioneze cu intrarea/ie³irea
standard, sau cu orice alt ³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 ³ierul advisor.h în programul advisor ³i
assistant.h în programul assistant. Acest lucru poate realizat inserând în surs linia:
#include "advisor.h"
sau
#include "assistant.h"
Cele dou ³iere advisor.h ³i assistant.h vor 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 realizat inserând în surs linia:
uses advisorlib;
sau
uses assistantlib;
Let us rst 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
scaold 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 scaold): this way
we might specify exactly which color (within the K colors available on the scaold) 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 scaold between active and passive: an active color
is one that will be requested before it is removed from the scaold 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 specied 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.
28
29 Color () {}
30
31 Color (int _id, int _np)
32 {
33 id = _id;
34 np = _np;
35 }
36 };
37
38 bool operator< (Color const &a, Color const &b)
39 {
40 return ( a.np < b.np );
41 }
42
43 int vnext[MAXN]; // vnext[i] = index of next occurrence of d[i] in array d
44 // (n if it is the last occurrence)
45 int position[MAXN]; // position[j] = index of the next occurrence of color j
46 // in array d (n if it is the last occurrence)
47
48 bool in_scaffolda[MAXN]; // whether color j is in the scaffold or not
49
50 priority_queue<Color> coda;
51
52 int solution[MAXN]; // -1 if no change is necessary,
53 // otherwise the color to be removed
54
55 queue<int> events[MAXN]; // events[j] is the queue of the events of color j:
56 // 1 = used; 0 = removed.
57
58 int accumulated = 0;
59 int counter = 0;
60
61 void ComputeAdvice (int *d, int n, int k, int m)
62 {
63 // Finding the next occurrence of each color
64 for (int i=0; i<n; ++i)
65 {
66 position[i] = n;
67 }
68
69 for (int i=n-1; i>=0; --i)
70 {
71 vnext[i] = position[d[i]];
72 position[d[i]] = i;
73 }
74
75 // Initial settings: inserting colors 0,...,k in the player
76 for (int j=0; j<k; ++j)
77 {
78 in_scaffolda[j] = 1;
79 coda.push( Color( j, position[j] ) );
80 }
81
82 // Finding the solution
83 for (int i=0; i<n; ++i)
84 {
85
86 int color = d[i];
87 if ( in_scaffolda[color] )
88 {
89 coda.push( Color( color, vnext[i] ) );
90 solution[i] = -1;
91 events[ color ].push( 1 );
92 continue;
93 }
94
95 // Removing useless color in scaffold
96 Color useless = coda.top();
97 coda.pop();
98 in_scaffolda[ useless.id ] = 0;
99
100 // Inserting new color in scaffold
101 coda.push( Color( color, vnext[i] ) );
102 in_scaffolda[ color ] = 1;
103
CAPITOLUL 9. IOI 2012 1025
180 if ( !in_the_scaffold[color] )
181 {
182
183 in_the_scaffold[ passive.front() ] = 0;
184 in_the_scaffold[ color ] = 1;
185
186 PutBack( passive.front() );
187 passive.pop();
188
189 }
190
191 if ( real_advice[k+i] == 0 ) passive.push(color);
192 }
193 }
194
195 // ------------------- begin grader ----------------------
196
197 #ifndef TRUE
198 #define TRUE 1
199 #endif
200 #ifndef FALSE
201 #define FALSE 0
202 #endif
203
204 #define inbuf_len 1 << 16
205 #define outbuf_len 1 << 16
206
207 static int N, K, M;
208 static int *C;
209
210 static int R;
211 static unsigned char *A;
212
213 static FILE *fadvice;
214
215 static int current_request = -1;
216 static int *in_scaffold;
217 static int expect_put_back;
218
219 int GetRequest(void)
220 {
221 int req;
222
223 if (expect_put_back)
224 {
225 fprintf(stderr, "Not putting back color when it is not on the scaffold\n");
226 exit(1);
227 }
228
229 req = C[++current_request];
230
231 if (!in_scaffold[req])
232 expect_put_back = TRUE;
233 else
234 expect_put_back = FALSE;
235
236 printf("R %d\n", req);
237 return req;
238 }
239
240 void PutBack(int T)
241 {
242 int req;
243
244 if (!expect_put_back)
245 {
246 fprintf(stderr,"Putting back a color when it is already on the scaffold\n");
247 exit(1);
248 }
249
250 if (!in_scaffold[T])
251 {
252 fprintf(stderr, "Putting back a color that is not on the scaffold\n");
253 exit(1);
254 }
255
CAPITOLUL 9. IOI 2012 1027
52
53 continue ;
54 }
55
56 auto par = *prev(s.end()) ;
57 s.erase( prev( s.end() ) ) ;
58
59 scaffold[ par.ss ] = false ;
60 scaffold[ C[i] ] = true ;
61
62 is_active[ active[par.ss] ] = true ;
63
64 int x = get_next( C[i] ) ;
65 if( x <= i ) x = get_next(C[i]) ;
66
67 s.insert( mk( x , C[i] ) ) ;
68 }
69
70 lp(i,0,K) WriteAdvice( is_active[N+i] ) ;
71 lp(i,0,N) WriteAdvice( is_active[i] ) ;
72 }
73
74 // ----------------- assistant ----------------
75
76 #define lp(i,a,b) for(int i = a ; i < b ; i++)
77 #define pii pair<int,int>
78 #define pb push_back
79 #define mk make_pair
80 #define ff first
81 #define ss second
82
83 //const int MAXN = 1e5+10 ;
84
85 using namespace std ;
86
87 set<int> actives ;
88 bool scaff[MAXN] ;
89
90 void Assist(unsigned char *A, int N, int K, int R)
91 {
92 int idx = -1 ;
93 lp(i,0,K)
94 {
95 scaff[i] = true ;
96 if( A[++idx] ) actives.insert(i) ;
97 }
98
99 lp(i,0,N)
100 {
101 int x = GetRequest() ;
102 if( scaff[x] )
103 {
104 if( A[++idx] ) actives.insert( x ) ;
105 continue ;
106 }
107
108 scaff[x] = true ;
109
110 int toErase = *actives.begin() ;
111 actives.erase( actives.begin() ) ;
112
113 scaff[ toErase ] = false ;
114
115 PutBack(toErase) ;
116
117 if( A[++idx] ) actives.insert(x) ;
118
119 }
120 }
121
122 // ------------------- begin grader ----------------------
123
124 #ifndef TRUE
125 #define TRUE 1
126 #endif
127 #ifndef FALSE
CAPITOLUL 9. IOI 2012 1030
204 exit(1);
205 };
206 }
207
208 static inline void input_assert(int ok)
209 {
210 if (!ok)
211 {
212 fprintf(stderr, "Invalid input file.\n");
213 exit(1);
214 }
215 }
216
217 int main()
218 {
219 auto t1 = clock();
220
221 std::freopen("../input/input50.txt", "r", stdin);
222 std::freopen("supper.out", "w", stdout);
223
224 int tmp;
225 int i;
226
227 /* Set input and output buffering */
228 char *inbuf, *outbuf;
229 inbuf = (char*) malloc(inbuf_len * sizeof(char));
230 outbuf = (char*) malloc(outbuf_len * sizeof(char));
231 tmp = setvbuf(stdin, inbuf, _IOFBF, inbuf_len);
232 tmp = setvbuf(stdout, outbuf, _IOFBF, outbuf_len);
233
234 fadvice = fopen("advice.txt", "w");
235
236 tmp = scanf("%d %d %d", &N, &K, &M);
237 input_assert(tmp == 3);
238
239 C = (int*) malloc(N * sizeof(int));
240 for (i = 0; i < N; i++)
241 {
242 tmp = scanf("%d", &C[i]);
243 input_assert(tmp == 1);
244 }
245
246 auto t2 = clock();
247
248 A = (unsigned char*) malloc(M * sizeof(int));
249
250 ComputeAdvice(C, N, K, M);
251
252 fprintf(fadvice, "\n2\n");
253
254 auto t3 = clock();
255
256 /* Init the scaffold */
257 in_scaffold = (int*) malloc(N * sizeof(int));
258 for (i = 0; i < K; i++)
259 in_scaffold[i] = TRUE;
260 for (i = K; i < N; i++)
261 in_scaffold[i] = FALSE;
262
263 Assist(A, N, K, R);
264
265 printf("E\n");
266
267 auto t4 = clock();
268
269 // reset console output
270 freopen("CON", "w", stdout);
271
272 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
273 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
274 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
275
276 return 0;
277 }
278 // ------------------- end grader ----------------------
CAPITOLUL 9. IOI 2012 1032
9.6 Tournament
Problema 6 - Turnirul 100 de puncte
Author: Luke Harrison
Î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 desemnate de arbitru pentru cele C runde. La urma urmei el e Leonardo, ... ³i el
este sigur c în ecare 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 ecare 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 [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 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
cavalerul cu rangul R 3. Dup acest rund rangurile cavalerilor din linie vor [3, 4]. Runda
nala (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 ind 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 ind cel cu rangul R 3. Linia nal este format din cavalerii cu rangurile [3,
4], câ³tig tor ind 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 e 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 9. IOI 2012 1033
Toate apelurile acestei rutine vor corecte: E i va 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 semnic faptul c cavalerul
întârziat este la începutul liniei, iar P N 1 semnic 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.
Subtask 3 [51 de puncte]
Se considr c N & 100 000.
Detalii de implementare
Trebuie s transmiµi exact un singur ³ier, denumit tournament.c\verb,
tournament.cpp sau tournament.pas. Acest µier trebuie s implementeze subprogramul
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 ³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 tournamentâs 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 nding 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 nd 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 donât need to actually try a position to see how
far up we can go: it is sucient to proceed as described in the rst 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.
24 {
25 int start;
26 int end;
27
28 bool all_white; // True if the interval contains good knights only
29 bool almost_all_white; // True if the interval contains good knights only,
30 // except at most the first knight
31
32 int best_result; // The maximum length of a victory-path finishing in
33 // that node
34 int where_best; // Where is the best_result achieved
35
36 Node() {}
37
38 Node(int _start, int _end)
39 {
40 start = _start;
41 end = _end;
42 best_result = 0;
43 }
44 };
45
46 int n,c,o;
47
48 bool rankb[MAXN];
49
50 // Range tree
51 int range_tree[MAXLOGN][MAXN];
52 int size_of_the_range_tree; // the size of the range tree
53
54 void make_range_tree()
55 {
56
57 int m = n;
58 int step = 0;
59
60 while ( m > 0 )
61 {
62 for (int i=0; i<m; ++i)
63 {
64 if ( step == 0 ) range_tree[step][i] = 1;
65 else
66 {
67 range_tree[step][i] = range_tree[step-1][2*i] +
68 range_tree[step-1][2*i+1];
69 }
70 }
71
72 if ( m > 1 ) m = (m+1)/2;
73 else m = 0;
74 step++;
75 }
76
77 size_of_the_range_tree = step;
78
79 }
80
81 void change (int k, int delta)
82 { // Change the value of position k by delta
83 int m = k;
84 for (int step = 0; step < size_of_the_range_tree; ++step)
85 {
86 range_tree[step][m] += delta;
87 m /= 2;
88 }
89 }
90
91 int find_knight (int k, int step, int m)
92 { // Find the (initial) position of the k-th living knight,
93 // starting from a given node (step,m) of the range tree
94 if ( k > range_tree[step][m] ) return n;
95
96 if ( step == 0 )
97 {
98 assert(k == 1);
99 return m;
CAPITOLUL 9. IOI 2012 1036
100 }
101
102 if ( range_tree[step-1][2*m] >= k )
103 return find_knight( k, step-1, 2*m );
104 else
105 return find_knight( k - range_tree[step-1][2*m], step-1, 2*m+1 );
106 }
107
108 // Calls tree
109
110 vector<Node> calls_tree;
111
112 int father[MAXN]; // The index of current interval of the knight
113
114 int GetBestPosition(int N, int C, int R, int *K, int *S, int *E)
115 {
116 n = N;
117 c = C;
118 int o = R;
119
120 make_range_tree();
121
122 rankb[0] = 1;
123 Node nodo = Node( 0, 0 );
124 nodo.all_white = 1;
125 nodo.almost_all_white = 1;
126 nodo.where_best = 0;
127 calls_tree.push_back( nodo );
128 father[0] = 0;
129
130 for (int i=1; i<n; ++i)
131 {
132 int r = K[i-1];
133 rankb[i] = (r > o);
134 father[i] = i;
135
136 Node nodo = Node( i, i );
137 nodo.all_white = !rankb[i];
138 nodo.almost_all_white = 1;
139 nodo.where_best = i;
140 calls_tree.push_back( nodo );
141 }
142
143 for (int i=0; i<c; ++i)
144 {
145 int s = S[i]+1;
146 int e = E[i]+1;
147
148 int first = find_knight( s, size_of_the_range_tree-1, 0 );
149 int last = find_knight( e+1, size_of_the_range_tree-1, 0 ) - 1;
150
151 Node interval = Node( first, last ); // The new interval
152
153 bool all_white = 1;
154 bool almost_all_white = 1;
155
156 int best_child = -1;
157 int the_best = -1;
158
159 queue<int> to_change;
160
161 for (int j=s; j<=e; ++j)
162 {
163
164 int knight = find_knight( j, size_of_the_range_tree-1, 0 );
165 if ( j > s ) to_change.push( knight );
166 int old_int = father[knight];
167
168 father[knight] = calls_tree.size();
169
170 if ( calls_tree[old_int].all_white == 0 )
171 {
172 all_white = 0;
173
174 if ( j > s ) almost_all_white = 0;
175 else
CAPITOLUL 9. IOI 2012 1037
176 if ( calls_tree[old_int].almost_all_white == 0 )
177 almost_all_white = 0;
178 }
179
180 if ( calls_tree[old_int].best_result > the_best )
181 {
182 the_best = calls_tree[old_int].best_result;
183 best_child = old_int;
184 }
185 }
186
187 while ( !(to_change.empty()) )
188 {
189 int knight = to_change.front();
190 to_change.pop();
191 change( knight, -1 );
192 }
193
194 interval.all_white = all_white;
195 interval.almost_all_white = almost_all_white;
196
197 if ( almost_all_white )
198 {
199 interval.best_result = the_best + 1;
200 interval.where_best = calls_tree[ best_child ].where_best;
201 // Found an interval for which it is possible
202 // to win interval.best_result times by starting in
203 // position interval.where_best
204 }
205 else
206 {
207 interval.best_result = the_best;
208 interval.where_best = calls_tree[ best_child ].where_best;
209 }
210
211 calls_tree.push_back(interval);
212 }
213
214 int t = calls_tree.size();
215
216 return calls_tree[t-1].where_best;
217 }
218
219 // -------------- begin grader -------------------------
220
221 int main()
222 {
223 auto t1 = clock();
224
225 std::freopen("../input/input30.txt", "r", stdin);
226 std::freopen("tournament.out", "w", stdout);
227
228 int tmp;
229
230 /* Set input and output buffering */
231 char *inbuf, *outbuf;
232 inbuf = (char*) malloc(inbuf_len * sizeof(char));
233 outbuf = (char*) malloc(outbuf_len * sizeof(char));
234 tmp = setvbuf(stdin, inbuf, _IOFBF, inbuf_len);
235 assert(tmp == 0);
236 tmp = setvbuf(stdout, outbuf, _IOFBF, outbuf_len);
237 assert(tmp == 0);
238
239 auto t2 = clock();
240
241 int N, C, R;
242 int *K, *S, *E;
243 tmp = scanf("%d %d %d", &N, &C, &R);
244 assert(tmp == 3);
245 K = (int*) malloc((N-1) * sizeof(int));
246 S = (int*) malloc(C * sizeof(int));
247 E = (int*) malloc(C * sizeof(int));
248 int i;
249 for (i = 0; i < N-1; i++)
250 {
251 tmp = scanf("%d", &K[i]);
CAPITOLUL 9. IOI 2012 1038
41 int GetBestPosition(int N, int C, int R, int *K, int *S, int *E)
42 {
43 int i,peo,x,y;
44
45 for (i=0;i<N;i++) nextv[i] = i+1, cnt[i+Z] = 1;
46 for (i=Z-1;i>=1;i--) cnt[i] = cnt[i*2] + cnt[i*2+1];
47
48 for (i=0;i<C;i++)
49 {
50 peo = E[i] - S[i];
51 S[i] = getnth(S[i]+1);
52 x = nextv[S[i]];
53 while (peo--)
54 {
55 up(x,-1);
56 x = nextv[x];
57 }
58 E[i] = x - 1;
59 nextv[S[i]] = x;
60 }
61
62 for (i=1;i<N;i++) add[i] = add[i-1] + (K[i-1] > R);
63
64 for (i=0;i<C;i++)
65 {
66 if (add[E[i]] == add[S[i]])
67 {
68 res[S[i]]++;
69 res[E[i]]--;
70 }
71 }
72
73 int s = 0, p = -1, ind;
74 for (i=0;i<N;i++)
75 {
76 s += res[i];
77 if (p < s)
78 {
79 p = s;
80 ind = i;
81 }
82 }
83
84 return ind;
85 }
86
87 // -------------- begin grader -------------------------
88
89 int main()
90 {
91 auto t1 = clock();
92
93 std::freopen("../input/input30.txt", "r", stdin);
94 std::freopen("tournament.out", "w", stdout);
95
96 int tmp;
97
98 /* Set input and output buffering */
99 char *inbuf, *outbuf;
100 inbuf = (char*) malloc(inbuf_len * sizeof(char));
101 outbuf = (char*) malloc(outbuf_len * sizeof(char));
102 tmp = setvbuf(stdin, inbuf, _IOFBF, inbuf_len);
103 assert(tmp == 0);
104 tmp = setvbuf(stdout, outbuf, _IOFBF, outbuf_len);
105 assert(tmp == 0);
106
107 auto t2 = clock();
108
109 int N, C, R;
110 int *K, *S, *E;
111 tmp = scanf("%d %d %d", &N, &C, &R);
112 assert(tmp == 3);
113 K = (int*) malloc((N-1) * sizeof(int));
114 S = (int*) malloc(C * sizeof(int));
115 E = (int*) malloc(C * sizeof(int));
116 int i;
CAPITOLUL 9. IOI 2012 1040
39 {
40 ret=max(ret,T[a]);
41 ret=max(ret,T[b]);
42 a = (a+1)>>1, b = (b-1)>>1;
43 }
44 return ret;
45 }
46
47 int sum[100010],ans;
48 int d[100010];
49
50 int GetBestPosition(int N, int C, int R, int *K, int *S, int *E)
51 {
52 int i;
53 for(i=0;i<N;i++)d[i]=i+1,T[i+idx]=1;
54 for(i=idx-1;i;i--)T[i]=T[i<<1] + T[i<<1|1];
55 for(i=0;i<C;i++)
56 {
57 int a = read1(S[i]+1);
58 int tmp = a;
59 for(int j=0;j<E[i]-S[i];j++)
60 {
61 tmp = d[tmp];
62 update(tmp);
63 }
64 d[a] = d[tmp];
65 E[i] = d[tmp]-1;
66 S[i] = a;
67 }
68 for(i=0;i<N-1;i++)T[i+idx]=K[i];
69 for(i=idx-1;i;i--)T[i]=max(T[i<<1],T[i<<1|1]);
70 for(i=0;i<C;i++)
71 {
72 int s = read2(S[i],E[i]-1);
73 if(s<R)sum[S[i]]++,sum[E[i]+1]--;
74 }
75 for(i=0;i<N;i++)sum[i]+=sum[i-1];
76 for(i=0;i<N;i++)if(sum[ans]<sum[i])ans=i;
77 return ans;
78 }
79
80 // -------------- begin grader -------------------------
81
82 int main()
83 {
84 auto t1 = clock();
85
86 std::freopen("../input/input30.txt", "r", stdin);
87 std::freopen("tournament.out", "w", stdout);
88
89 int tmp;
90
91 /* Set input and output buffering */
92 char *inbuf, *outbuf;
93 inbuf = (char*) malloc(inbuf_len * sizeof(char));
94 outbuf = (char*) malloc(outbuf_len * sizeof(char));
95 tmp = setvbuf(stdin, inbuf, _IOFBF, inbuf_len);
96 assert(tmp == 0);
97 tmp = setvbuf(stdout, outbuf, _IOFBF, outbuf_len);
98 assert(tmp == 0);
99
100 auto t2 = clock();
101
102 int N, C, R;
103 int *K, *S, *E;
104 tmp = scanf("%d %d %d", &N, &C, &R);
105 assert(tmp == 3);
106 K = (int*) malloc((N-1) * sizeof(int));
107 S = (int*) malloc(C * sizeof(int));
108 E = (int*) malloc(C * sizeof(int));
109 int i;
110 for (i = 0; i < N-1; i++)
111 {
112 tmp = scanf("%d", &K[i]);
113 assert(tmp == 1);
114 }
CAPITOLUL 9. IOI 2012 1042
43
44 void init(int n)
45 {
46 for(lim = 1; lim <= n; lim <<= 1);
47 for(int i=1; i<=n; i++) add(i,1);
48 }
49 } bit;
50
51 struct rmq
52 {
53 int tree[265000], lim;
54 void init(int n, int* a)
55 {
56 for(lim = 1; lim <= n; lim <<= 1);
57 for(int i=0; i<n; i++)
58 {
59 tree[lim + i + 1] = a[i];
60 }
61
62 for(int i=lim-1; i; i--)
63 {
64 tree[i] = max(tree[2*i],tree[2*i+1]);
65 }
66 }
67
68 int q(int s, int e)
69 {
70 int ret = 0;
71 s += lim;
72 e += lim;
73 while(s < e)
74 {
75 if(s%2 == 1) ret = max(ret,tree[s++]);
76 if(e%2 == 0) ret = max(ret,tree[e--]);
77 s >>= 1;
78 e >>= 1;
79 }
80 if(s == e) ret = max(ret,tree[s]);
81 return ret;
82 }
83 } rmq;
84
85 int dx[100005];
86
87 int GetBestPosition(int N, int C, int R, int *K, int *S, int *E)
88 {
89 for (int i=0; i<C; i++)
90 {
91 S[i]++;
92 E[i]++;
93 }
94 bit.init(N);
95 rmq.init(N-1,K);
96 for (int i=0; i<C; i++)
97 {
98 int st = bit.lbnd(S[i]);
99 int ed = bit.lbnd(E[i] + 1) - 1;
100 for (int j=E[i]; j>S[i]; j--)
101 {
102 bit.add(bit.lbnd(j),-1);
103 }
104 S[i] = st;
105 E[i] = min(ed,N)-1;
106 if(rmq.q(S[i],E[i]) < R)
107 {
108 dx[S[i]]++;
109 dx[E[i]+1]--;
110 }
111 }
112 for (int i=1; i<=N-1; i++)
113 {
114 dx[i] += dx[i-1];
115 }
116 return (int)(max_element(dx+1,dx+N) - dx - 1);
117 }
118
CAPITOLUL 9. IOI 2012 1044
7 {
8 int argc=4;
9
10 char* argv[] =
11 {
12 (char*)"checker",
13 (char*)"../input/input30.txt",
14 (char*)"tournament.out",
15 (char*)"../output/output30.txt",
16 };
17
18 cout<<"argc = "<<argc<<"\n";
19 for(int kk=0;kk<argc;kk++)
20 cout<<argv[kk]<<"\n";
21 cout<<"----------------------\n";
22
23 registerChecker("tournament", argc, argv);
24 compareRemainingLines();
25 }
IOI 201135
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 dierent 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 dierent for each group of
students.
Somhed wonders how many dierent 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 nish 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
nish their route at fountain number P .
Your task
Given the information on the fountains and the trails, you have to nd 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.
35
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).
1046
CAPITOLUL 10. IOI 2011 1047
For 0 & i $ Q, your procedure must nd 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 rst 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 rst group, there is only one valid route that rea-
ches 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 rst call answer(1) to report the answer for the rst 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.
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 les 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 specied 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 ecient 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
¬
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.
CAPITOLUL 10. IOI 2011 1049
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 rst 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
rst 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 nd 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 sucient 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 rst 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 specied 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 nd the destination of each path in
O log K . Thus, the total running time is O M N Q log K , which is sucient 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 rst 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 .
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 .
CAPITOLUL 10. IOI 2011 1050
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-rst 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 rst 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 rst create an array for storing Fs for each vertex s. We then initialize Fs and C
to 1, and update them during the depth-rst search. We perform the search twice, starting at vP
¬
and vP , respectively.
Since the depth-rst 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 sucient
to obtain full marks for this task.
33 bool visit[2*MAXN];
34 int ans1[2*MAXN], ans2[2*MAXN];
35
36 void run(int P, int dist, int *ans, int &res, int oP)
37 {
38 if(visit[P])
39 {
40 if(P == oP) res = dist;
41 return;
42 }
43 visit[P] = true;
44 if(P<N) ans[dist]++;
45 for(auto x: inlist[P])
46 run(x, dist+1, ans, res, oP);
47 }
48
49 void count_routes(int _N, int M, int P, int R[][2], int Q, int G[])
50 {
51 N = _N;
52 for(int i=0; i<N; ++i) minv1[i] = minv2[i] = -1;
53 for(int i=0; i<M; ++i)
54 {
55 int u = R[i][0], v = R[i][1];
56 for(int x: {u, v})
57 {
58 int y = u+v-x;
59 if(minv1[x] == -1) minv1[x] = y;
60 else if(minv2[x] == -1) minv2[x] = y;
61 }
62 }
63
64 for(int i=0; i<N; ++i)
65 if(minv2[i] == -1)
66 minv2[i] = minv1[i];
67
68 for(int i=0; i<2*N; ++i)
69 {
70 int to = (i<N) ? minv1[i%N] : minv2[i%N];
71 if(i%N == minv1[to]) to += N;
72 outlist[i] = to;
73 inlist[to].push_back(i);
74 }
75
76 int res1 = 0x3f3f3f3f, res2 = 0x3f3f3f3f;
77 run(P, 0, ans1, res1, P);
78 for(int i=0; i<2*N; ++i) visit[i] = false;
79 run(P+N, 0, ans2, res2, P+N);
80
81 for(int i=0; i<Q; ++i)
82 {
83 int ans = 0;
84 for(int j=G[i]%res1; j<=G[i] && j <= N; j += res1)
85 ans += ans1[j];
86 for(int j=G[i]%res2; j<=G[i] && j <= N; j += res2)
87 ans += ans2[j];
88 answer(ans);
89 }
90 return ;
91 }
92
93 // ------------- begin grader -----------------------
94
95 void read_input()
96 {
97 int i;
98 my_assert(3==scanf("%d %d %d",&N,&M,&P));
99 for(i=0; i<M; i++)
100 my_assert(2==scanf("%d %d",&R[i][0],&R[i][1]));
101 my_assert(1==scanf("%d",&Q));
102 for(i=0; i<Q; i++)
103 my_assert(1==scanf("%d",&G[i]));
104 for(i=0; i<Q; i++)
105 my_assert(1==scanf("%d",&solutions[i]));
106 }
107
108 void answer(int x)
CAPITOLUL 10. IOI 2011 1052
109 {
110 if(answer_count>=Q)
111 {
112 printf("Incorrect. Too many answers.\n");
113 exit(0);
114 }
115 answers[answer_count] = x;
116 answer_count++;
117 }
118
119 int main()
120 {
121 auto t1 = clock();
122
123 std::freopen("../tests/subtask3/grader.in.14", "r", stdin);
124 std::freopen("garden.out", "w", stdout);
125
126 int correct, i;
127
128 read_input();
129
130 auto t2 = clock();
131
132 answer_count = 0;
133 count_routes(N,M,P,R,Q,G);
134
135 auto t3 = clock();
136
137 if(answer_count!=Q)
138 {
139 printf("Incorrect. Too few answers.\n");
140 exit(0);
141 }
142
143 correct = 1;
144 for(i=0; i<Q; i++)
145 if(answers[i]!=solutions[i])
146 correct = 0;
147
148 if(correct)
149 printf("Correct.\n");
150 else
151 {
152 printf("Incorrect.\n");
153 printf("Expected: ");
154 for(i=0; i<Q; i++)
155 printf("%d ",solutions[i]);
156 printf("\nReturned: ");
157 for(i=0; i<Q; i++)
158 printf("%d ",answers[i]);
159 }
160
161 auto t4 = clock();
162
163 // reset console output
164 freopen("CON", "w", stdout);
165
166 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
167 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
168 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
169 return 0;
170 }
171
172 // ------------- end grader -----------------------
173 /*
174 t2-t1 = 0.484
175 t3-t2 = 0.235
176 t4-t3 = 0
177
178 Process returned 0 (0x0) execution time : 0.781 s
179 Press any key to continue.
180 */
1 // https://oj.uz/submission/49789 69 ms 13788 KB
2
3 #include "garden.h"
4 #include "gardenlib.h"
5
6 #include<ctime>
7 #include<iostream>
8
9 #define MAX_M 1000000
10 #define MAX_Q 2000
11
12 static int N, M, P, Q;
13 static int R[MAX_M][2];
14 static int G[MAX_Q];
15 static int solutions[MAX_Q];
16 static int answers[MAX_Q];
17 static int answer_count;
18
19 inline void my_assert(int e) {if (!e) abort();}
20
21 #include <cstring>
22
23 using namespace std;
24
25 void answer(int x);
26
27 const int MAXN = 150000;
28 const int MAXN2 = MAXN * 2;
29
30 int arr[MAXN2 + 10];
31 int dis[2][MAXN2 + 10];
32 bool chk[2][MAXN2 + 10];
33
34 void f(int x, int p)
35 {
36 chk[p % 2][x] = 1;
37 if(arr[x] == p)
38 {
39 dis[p % 2][x] = 1;
40 return;
41 }
42
43 if(!chk[p % 2][arr[x]])
44 f(arr[x], p);
45
46 if(dis[p % 2][arr[x]])
47 dis[p % 2][x] = dis[p % 2][arr[x]] + 1;
48 }
49
50 int mem1[MAXN + 10];
51 int mem2[MAXN + 10];
52 int sum[2][MAXN2 + 10];
53
54 void count_routes(int N, int M, int P, int R[][2], int Q, int G[])
55 {
56 memset(mem1, -1, sizeof mem1);
57 memset(mem2, -1, sizeof mem2);
58 memset(arr, -1, sizeof arr);
59
60 for(int i = 0; i < M; i++)
61 {
62 int x = R[i][0];
63 int y = R[i][1];
64
65 if(mem1[x] == -1)
66 mem1[x] = y;
67 else if(mem2[x] == -1)
68 mem2[x] = y;
69
70 if(mem1[y] == -1)
71 mem1[y] = x;
72 else if(mem2[y] == -1)
73 mem2[y] = x;
74 }
75
76 for(int i = 0; i < N; i++)
CAPITOLUL 10. IOI 2011 1054
77 {
78 if(mem1[mem1[i]] == i && mem2[mem1[i]] != -1)
79 arr[2 * i] = 2 * mem1[i] + 1;
80 else
81 arr[2 * i] = 2 * mem1[i];
82
83 if(mem2[i] != -1)
84 {
85 if(mem1[mem2[i]] == i && mem2[mem2[i]] != -1)
86 arr[2 * i + 1] = 2 * mem2[i] + 1;
87 else
88 arr[2 * i + 1] = 2 * mem2[i];
89 }
90 }
91
92 for(int r = 0; r < 2; r++)
93 for(int i = 0; i < 2 * N; i++)
94 if(!chk[r][i] && arr[i] != -1)
95 f(i, 2 * P + r);
96
97 for(int r = 0; r < 2; r++)
98 for(int i = 0; i < N; i++)
99 if(dis[r][2 * i])
100 sum[r][dis[r][2 * i]]++;
101
102 for(int r = 0; r < 2; r++)
103 {
104 int c = dis[r][2 * P + r];
105 if(!c)
106 continue;
107
108 for(int i = 1; i <= 2 * N; i++)
109 if(i - c >= 1)
110 sum[r][i] += sum[r][i - c];
111 }
112
113 int c[2] = { dis[0][2 * P], dis[1][2 * P + 1] };
114
115 if(!c[0])
116 c[0] = c[1];
117 if(!c[1])
118 c[1] = c[0];
119 for(int i = 0; i < Q; i++)
120 {
121 int ans = 0;
122 for(int r=0;r<2;r++)
123 {
124 int t = G[i];
125 if(t > 2 * N && c[r])
126 t -= ((t - 2 * N + c[r] - 1) / c[r]) * c[r];
127
128 if(t <= 2 * N)
129 ans += sum[r][t];
130 }
131 answer(ans);
132 }
133 }
134
135 // ------------- begin grader -----------------------
136
137 void read_input()
138 {
139 int i;
140 my_assert(3==scanf("%d %d %d",&N,&M,&P));
141 for(i=0; i<M; i++)
142 my_assert(2==scanf("%d %d",&R[i][0],&R[i][1]));
143 my_assert(1==scanf("%d",&Q));
144 for(i=0; i<Q; i++)
145 my_assert(1==scanf("%d",&G[i]));
146 for(i=0; i<Q; i++)
147 my_assert(1==scanf("%d",&solutions[i]));
148 }
149
150 void answer(int x)
151 {
152 if(answer_count>=Q)
CAPITOLUL 10. IOI 2011 1055
153 {
154 printf("Incorrect. Too many answers.\n");
155 exit(0);
156 }
157 answers[answer_count] = x;
158 answer_count++;
159 }
160
161 int main()
162 {
163 auto t1 = clock();
164
165 std::freopen("../tests/subtask3/grader.in.14", "r", stdin);
166 std::freopen("garden.out", "w", stdout);
167
168 int correct, i;
169
170 read_input();
171
172 auto t2 = clock();
173
174 answer_count = 0;
175 count_routes(N,M,P,R,Q,G);
176
177 auto t3 = clock();
178
179 if(answer_count!=Q)
180 {
181 printf("Incorrect. Too few answers.\n");
182 exit(0);
183 }
184
185 correct = 1;
186 for(i=0; i<Q; i++)
187 if(answers[i]!=solutions[i])
188 correct = 0;
189 if(correct)
190 printf("Correct.\n");
191 else
192 {
193 printf("Incorrect.\n");
194 printf("Expected: ");
195 for(i=0; i<Q; i++)
196 printf("%d ",solutions[i]);
197 printf("\nReturned: ");
198 for(i=0; i<Q; i++)
199 printf("%d ",answers[i]);
200 }
201
202 auto t4 = clock();
203
204 // reset console output
205 freopen("CON", "w", stdout);
206
207 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
208 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
209 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
210 return 0;
211 }
212
213 // ------------- end grader -----------------------
214 /*
215 t2-t1 = 0.421
216 t3-t2 = 0.063
217 t4-t3 = 0
218
219 Process returned 0 (0x0) execution time : 0.500 s
220 Press any key to continue.
221 */
4 #include "gardenlib.h"
5 #include <stdio.h>
6 #include <stdlib.h>
7
8 #include<ctime>
9 #include<iostream>
10
11 #include <cstdio>
12 #include <vector>
13 #include <initializer_list>
14
15 #define MAX_M 1000000
16 #define MAX_Q 2000
17
18 static int N, M, P, Q;
19 static int R[MAX_M][2];
20 static int G[MAX_Q];
21 static int solutions[MAX_Q];
22 static int answers[MAX_Q];
23 static int answer_count;
24
25 inline void my_assert(int e) {if (!e) abort();}
26
27 #include <queue>
28
29 using namespace std;
30
31 const int INF=1e9+7;
32
33 static std::vector<int> adj[150005];
34 static int to[300005];
35 static std::vector<int> from[300005];
36
37 static int dist[2][300005];
38
39 static void bfs(int start,int* dist)
40 {
41 std::queue<int> q;
42 q.push(start);
43 while(!q.empty())
44 {
45 int node=q.front();
46 q.pop();
47 for(int child:from[node])
48 {
49 if(!dist[child])
50 {
51 dist[child]=dist[node]+1;
52 q.push(child);
53 }
54 }
55 }
56 }
57
58 void count_routes(int N, int M, int P, int R[][2], int Q, int G[])
59 {
60 for(int i=0;i<M;i++)
61 {
62 adj[R[i][0]].push_back(R[i][1]);
63 adj[R[i][1]].push_back(R[i][0]);
64 }
65
66 for(int i=0;i<N;i++)
67 {
68 to[i<<1]=(adj[i][0]<<1)|(i==adj[adj[i][0]][0]);
69 if(adj[i].size()>1)
70 {
71 to[i<<1|1]=(adj[i][1]<<1)|(i==adj[adj[i][1]][0]);
72 }
73 else
74 {
75 to[i<<1|1]=to[i<<1];
76 }
77 }
78
79 for(int i=0;i<N*2;i++)
CAPITOLUL 10. IOI 2011 1057
80 {
81 from[to[i]].push_back(i);
82 }
83 bfs(P<<1,dist[0]);
84 bfs(P<<1|1,dist[1]);
85 int cycle[2];
86 cycle[0]=dist[0][P<<1]?dist[0][P<<1]:INF;
87 cycle[1]=dist[1][P<<1|1]?dist[1][P<<1|1]:INF;
88 for(int q=0; q<Q; q++)
89 {
90 int K=G[q];
91 int ans=0;
92 for(int i=0;i<N*2;i+=2)
93 {
94 if(dist[0][i]) ans+=(K>=dist[0][i]&&(K-dist[0][i])%cycle[0]==0);
95 if(dist[1][i]) ans+=(K>=dist[1][i]&&(K-dist[1][i])%cycle[1]==0);
96 }
97 answer(ans);
98 }
99 }
100
101 // ------------- begin grader -----------------------
102
103 void read_input()
104 {
105 int i;
106 my_assert(3==scanf("%d %d %d",&N,&M,&P));
107 for(i=0; i<M; i++)
108 my_assert(2==scanf("%d %d",&R[i][0],&R[i][1]));
109 my_assert(1==scanf("%d",&Q));
110 for(i=0; i<Q; i++)
111 my_assert(1==scanf("%d",&G[i]));
112 for(i=0; i<Q; i++)
113 my_assert(1==scanf("%d",&solutions[i]));
114 }
115
116 void answer(int x)
117 {
118 if(answer_count>=Q) {
119 printf("Incorrect. Too many answers.\n");
120 exit(0);
121 }
122 answers[answer_count] = x;
123 answer_count++;
124 }
125
126 int main()
127 {
128 auto t1 = clock();
129
130 std::freopen("../tests/subtask3/grader.in.14", "r", stdin);
131 std::freopen("garden.out", "w", stdout);
132
133 int correct, i;
134
135 read_input();
136
137 auto t2 = clock();
138
139 answer_count = 0;
140 count_routes(N,M,P,R,Q,G);
141
142 auto t3 = clock();
143
144 if(answer_count!=Q)
145 {
146 printf("Incorrect. Too few answers.\n");
147 exit(0);
148 }
149
150 correct = 1;
151 for(i=0; i<Q; i++)
152 if(answers[i]!=solutions[i])
153 correct = 0;
154 if(correct)
155 printf("Correct.\n");
CAPITOLUL 10. IOI 2011 1058
156 else {
157 printf("Incorrect.\n");
158 printf("Expected: ");
159 for(i=0; i<Q; i++)
160 printf("%d ",solutions[i]);
161 printf("\nReturned: ");
162 for(i=0; i<Q; i++)
163 printf("%d ",answers[i]);
164 }
165
166 auto t4 = clock();
167
168 // reset console output
169 freopen("CON", "w", stdout);
170
171 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
172 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
173 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
174
175 return 0;
176 }
177
178 // ------------- end grader -----------------------
179 /*
180 t2-t1 = 0.109
181 t3-t2 = 2.985
182 t4-t3 = 0
183
184 Process returned 0 (0x0) execution time : 3.219 s
185 Press any key to continue.
186 */
10.2 Race
Problema 2 - Race 100 de puncte
Author: Martin Fixman
CAPITOLUL 10. IOI 2011 1059
In conjunction with the IOI, Pattaya City will host a race: the International Olympiad in
Racing (IOR) 2011. As the host, we have to nd 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 dierent 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 specic regulations that require the course to be a path whose total length is
exactly K kilometers, starting and ending in dierent cities. Obviously, no highway (and therefore
also no city) may be used twice on the course to prevent collisions. To minimize trac 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 10. IOI 2011 1060
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 les 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 nd if there exists a path of length exactly K that contains u.
If u is one of the endpoints in P , we can nd the path using one application of depth rst
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 nd x and y .
Consider some node w adjacent to u. With one application of DFS, we can nd the set Lw of
all path lengths for all paths starting at u and containing edge u, w.
Hence, to nd x and y , we need to nd 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 nd node u such that after deleting u, each resulting trees are all suciently
"small". In this case, we shall nd 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 rst.
¬
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 nd 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 d the central node in O N log N time and O N time.
2.1 Bottom-up approach
We can nd 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 nd 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 dened.
While performing DFS, we compute, for each node v , the number of its descendants D v .
With this information, we can gure 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 10. IOI 2011 1062
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 nding 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 nd 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 nding u that do not always work. Here are some examples.
32 {
33 d[0] = 0;
34 for (auto &y : v[x])
35 {
36 if (y.x == par) continue;
37 unordered_map <int, int> d2;
38 int L2 = 0, W2 = 0;
39 f(y.x, x, d2, L2, W2);
40 L2++;
41 W2 += y.w;
42 if (d.size() < d2.size())
43 {
44 d.swap(d2);
45 swap(L, L2);
46 swap(W, W2);
47 }
48
49 for (auto &t : d2)
50 {
51 if (d.count(K - (t.first + W2 + W)))
52 {
53 if (ans == -1 ||
54 ans > d[K - (t.first + W2 + W)] + t.second + L + L2)
55 ans = d[K - (t.first + W2 + W)] + t.second + L + L2;
56 }
57 }
58
59 for (auto &t : d2)
60 {
61 if (t.first + W2 > K) continue;
62 if (t.first + W2 == K)
63 {
64 if (ans == -1 || ans > t.second + L2)
65 ans = t.second + L2;
66 }
67 if (d.count(t.first + W2 - W))
68 d[t.first + W2 - W] = min(d[t.first + W2 - W],
69 t.second + L2 - L);
70 else
71 d[t.first + W2 - W] = t.second + L2 - L;
72 }
73 }
74 }
75
76 int best_path(int _N, int _K, int H[][2], int L[])
77 {
78 N = _N, K = _K;
79 for (int i = 0; i < N - 1; i++)
80 {
81 v[H[i][0]].push_back({ H[i][1], L[i] });
82 v[H[i][1]].push_back({ H[i][0], L[i] });
83 }
84
85 unordered_map <int, int> d;
86 int A = 0, B = 0;
87 f(0, -1, d, A, B);
88
89 return ans;
90 }
91
92 // ----------------------- begin grader -----------------
93
94 void read_input()
95 {
96 int i;
97 my_assert(2==scanf("%d %d",&N,&K));
98 for(i=0; i<N-1; i++)
99 my_assert(3==scanf("%d %d %d",&H[i][0],&H[i][1],&L[i]));
100 my_assert(1==scanf("%d",&solution));
101 }
102
103 int main()
104 {
105 auto t1 = clock();
106
107 std::freopen("../tests/subtask4/grader.in.16", "r", stdin);
CAPITOLUL 10. IOI 2011 1064
36 if(m[vx].find(k-w[vx]-w[vy]-i->F)!=m[vx].end())
37 ans=min(ans,m[vx][k-w[vx]-w[vy]-i->F] + i->S + la[vx]+la[vy]);
38 }
39
40 for(map<int,int>::iterator i=m[vy].begin();i!=m[vy].end();i++)
41 {
42 int c=i->F-w[vx]+w[vy];
43 if(m[vx].find(c)!=m[vx].end())
44 m[vx][c]=min(m[vx][c],i->S-la[vx]+la[vy]);
45 else
46 m[vx][c]=i->S-la[vx]+la[vy];
47 }
48
49 vs[y]=vx;
50 }
51
52 void dfs(int v,int p)
53 {
54 for(int i=0;i<g[v].size();i++)
55 {
56 int u=g[v][i].F,l=g[v][i].S;
57 if(u==p)continue;
58 dfs(u,v);
59 w[vs[u]]+=l;
60 la[vs[u]]++;
61 merge(v,u);
62 }
63 }
64
65 int best_path(int N,int K,int H[][2],int L[])
66 {
67 n=N;
68 k=K;
69 for(int i=0;i<n-1;i++)
70 {
71 int a=H[i][0],b=H[i][1],c=L[i];
72 g[a].PB(P(b,c));
73 g[b].PB(P(a,c));
74 }
75
76 for(int i=0;i<n;i++)
77 vs[i]=i,m[i][0]=0;
78
79 dfs(0,-1);
80
81 if(ans==INF)return -1;
82 else return ans;
83 }
84
85 // ----------------------- begin grader -----------------
86
87 void read_input()
88 {
89 int i;
90 my_assert(2==scanf("%d %d",&N,&K));
91 for(i=0; i<N-1; i++)
92 my_assert(3==scanf("%d %d %d",&H[i][0],&H[i][1],&L[i]));
93 my_assert(1==scanf("%d",&solution));
94 }
95
96 int main()
97 {
98 auto t1 = clock();
99
100 std::freopen("../tests/subtask4/grader.in.16", "r", stdin);
101 std::freopen("rase.out", "w", stdout);
102
103 int ans;
104 read_input();
105
106 auto t2 = clock();
107
108 ans = best_path(N,K,H,L);
109
110 auto t3 = clock();
111
CAPITOLUL 10. IOI 2011 1066
112 if(ans==solution)
113 printf("Correct.\n");
114 else
115 printf("Incorrect. Returned %d, Expected %d.\n",ans,solution);
116
117 auto t4 = clock();
118
119 // reset console output
120 freopen("CON", "w", stdout);
121
122 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
123 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
124 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
125
126 return 0;
127 }
128
129 // ----------------------- end grader -----------------
130 /*
131 t2-t1 = 0.734
132 t3-t2 = 1.532
133 t4-t3 = 0
134
135 Process returned 0 (0x0) execution time : 3.075 s
136 Press any key to continue.
137 */
47
48 //#define unx 1
49 #ifndef unx
50 #include "race.h"
51 #endif
52
53 const int NN=200010;
54
55 int n,cnt,k,ret;
56 int sz[NN],dd[NN],f[NN*5];
57 vector<ii> val;
58 vector<ii> ad[NN];
59
60 void dfs1(int u,int p=-1)
61 {
62 sz[u]=1; cnt++;
63 forv(v,ad[u])
64 if(!dd[v.fi] && v.fi!=p)
65 dfs1(v.fi,u), sz[u]+=sz[v.fi];
66 }
67
68 int ftr(int u,int p=-1)
69 {
70 forv(v,ad[u])
71 if(!dd[v.fi] && v.fi!=p && sz[v.fi]>cnt/2)
72 return ftr(v.fi,u);
73 return u;
74 }
75
76 void dfs2(int u,int p,int c,int d)
77 {
78 if(c>k) return;
79 val.push_back({c,d});
80 forv(v,ad[u])
81 if(!dd[v.fi] && v.fi!=p && v.se+c<=k)
82 dfs2(v.fi,u,c+v.se,d+1);
83 }
84
85 void ctr(int u)
86 {
87 cnt=0;
88 dfs1(u);
89 dd[u=ftr(u)]=1;
90
91 f[0]=0;
92 vector<int> reval;
93 forv(v,ad[u])
94 if(!dd[v.fi])
95 {
96 dfs2(v.fi,u,v.se,1);
97 forv(i,val)
98 if(f[k-i.fi]>-1)
99 ret=min(ret,i.se+f[k-i.fi]);
100 forv(i,val)
101 f[i.fi]=f[i.fi]<0 ? i.se :
102 min(f[i.fi],i.se), reval.push_back(i.fi);
103 val.clear();
104 }
105
106 forv(i,reval) f[i]=-1;
107
108 forv(v,ad[u])
109 if(!dd[v.fi]) ctr(v.fi);
110 }
111
112 int best_path(int n,int _k,int h[][2],int l[])
113 {
114 k=_k;
115 ret=n;
116 forinc(i,0,n-2)
117 {
118 int u=h[i][0], v=h[i][1], w=l[i];
119 ad[u].push_back({v,w});
120 ad[v].push_back({u,w});
121 }
122 reset(f,-1);
CAPITOLUL 10. IOI 2011 1068
123 ctr(0);
124 return ret<n ? ret : -1;
125 }
126
127 // ----------------------- begin grader -----------------
128
129 void read_input()
130 {
131 int i;
132 my_assert(2==scanf("%d %d",&N,&K));
133 for(i=0; i<N-1; i++)
134 my_assert(3==scanf("%d %d %d",&H[i][0],&H[i][1],&L[i]));
135 my_assert(1==scanf("%d",&solution));
136 }
137
138 int main()
139 {
140 auto t1 = clock();
141
142 std::freopen("../tests/subtask4/grader.in.16", "r", stdin);
143 std::freopen("rase.out", "w", stdout);
144
145 int ans;
146 read_input();
147
148 auto t2 = clock();
149
150 ans = best_path(N,K,H,L);
151
152 auto t3 = clock();
153
154 if(ans==solution)
155 printf("Correct.\n");
156 else
157 printf("Incorrect. Returned %d, Expected %d.\n",ans,solution);
158
159 auto t4 = clock();
160
161 // reset console output
162 freopen("CON", "w", stdout);
163
164 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
165 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
166 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
167
168 return 0;
169 }
170
171 // ----------------------- end grader -----------------
172 /*
173 t2-t1 = 0.188
174 t3-t2 = 1
175 t4-t3 = 0
176
177 Process returned 0 (0x0) execution time : 1.531 s
178 Press any key to continue.
179 */
16 };
17
18 cout<<"argc = "<<argc<<"\n";
19 for(int kk=0;kk<argc;kk++)
20 cout<<argv[kk]<<"\n";
21 cout<<"----------------------\n";
22
23 registerChecker("race", argc, argv);
24 compareRemainingLines();
25 }
In the countryside, you can nd a long straight road known as the Rice Way. Along this road
there are R rice elds. Each eld is located at an integer coordinate between 1 and L, inclusive.
The rice elds will be presented in non-decreasing order of their coordinates. Formally, for
0 & i $ R, rice eld i is at coordinate X i. You may assume that 1 & X 0 & ... & X R 1 & L.
Please note that multiple rice elds 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 elds, 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 elds.
Each rice eld 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 eld to the rice hub is numerically equal to the dierence 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 elds. The elds 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,
eld i is located at X i.
B - the budget.
Your procedure must nd 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 10. IOI 2011 1070
For this case, there are multiple optimal locations for the hub: you can place it anywhere
between locations 10 and 14, inclusive. The gure above shows one of these optimal locations.
You will then be able to transport rice from elds 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 elds, 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 elds 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 elds; 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 les should contain precisely the text Correct.
CAPITOLUL 10. IOI 2011 1071
The key insight to solving this problem is the observation that for any K rice elds located
at r0 & r1 & ... & rK 1 , the transportation cost from all these K elds 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 elds whose rice will be
transported to the hub). The cost of S is
cost S = ¶r j h S ¶,
rj "S
= X j .
i1
T i
j 0
where p s t©2$.
2
This O R algorithm suces to solve subtask 3.
3 An O R log R solution
Applying a binary search to nd the right length in place of a linear search improves the
running time to O R log R and suces 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 elds. In particular, imagine
adding in the rice elds one by one. In iteration i, we add ri and nd (1) Si i, the best solution
that uses only (a subsequence of) the rst i rice elds (i.e., Si N
r0 , ..., ri 1, and (2) Si , the
best solution that uses only (a subsequence of) the rst i rice elds 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 prex 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 10. IOI 2011 1072
Since cost
rs , ..., rt takes O 1 to compute, the running time of this algorithm is O R and
suces to solve all subtasks.
87 }
88
89 // --------------- end grader ---------------
90 /*
91 t2-t1 = 0.187
92 t3-t2 = 0
93 t4-t3 = 0
94
95 Process returned 0 (0x0) execution time : 0.266 s
96 Press any key to continue.
97 */
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 10. IOI 2011 1080
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 les 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 dened.
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
36
computed by producing the list rv " N w T v L w, v x, sorting this list, and returning
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.
112 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
113 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
114
115 return 0;
116 }
117
118 // -------------- begin grader -----------------
119 /*
120 t2-t1 = 0.922
121 t3-t2 = 2.704
122 t4-t3 = 0
123
124 Process returned 0 (0x0) execution time : 3.689 s
125 Press any key to continue.
126 */
58
59 n=_n; m=_m;
60
61 for(i=0;i<m;i++)
62 {
63 addEdge(R[i][0],R[i][1],L[i],i*2+1);
64 addEdge(R[i][1],R[i][0],L[i],i*2+2);
65 }
66
67 for(i=0;i<n;i++)
68 {
69 for(j=0;j<2;j++) d[j][i]=INF+1;
70 }
71
72 for(i=0;i<K;i++)
73 {
74 for(j=0;j<2;j++) d[j][P[i]]=0;
75 Q.push(Inque(P[i],0));
76 }
77
78 for(i=0;i<n;i++)
79 {
80 while(!Q.empty() && v[Q.top().x]) Q.pop();
81 if(Q.empty()) break;
82 Inque t=Q.top(); Q.pop();
83 if(t.x==0) break;
84 v[t.x]=true;
85 for(j=sta[t.x];j;j=nxt[j])
86 {
87 bool l=true;
88 if(d[0][chi[j]]>t.w+wei[j])
89 {
90 d[1][chi[j]]=d[0][chi[j]];
91 d[0][chi[j]]=t.w+wei[j];
92 }
93 else
94 if(d[1][chi[j]]>t.w+wei[j])
95 {
96 d[1][chi[j]]=t.w+wei[j];
97 }
98 else
99 {
100 l=false;
101 }
102
103 if(l)
104 {
105 if(d[1][chi[j]]!=INF+1)
106 {
107 Q.push(Inque(chi[j],d[1][chi[j]]));
108 }
109 }
110 }
111 }
112 return d[1][0];
113 }
114
115 // -------------- begin grader -----------------
116
117 void read_input()
118 {
119 int i;
120 my_assert(3==scanf("%d %d %d",&N,&M,&K));
121 for(i=0; i<M; i++)
122 my_assert(3==scanf("%d %d %d",&R[i][0],&R[i][1],&L[i]));
123 for(i=0; i<K; i++)
124 my_assert(1==scanf("%d",&P[i]));
125 my_assert(1==scanf("%d",&solution));
126 }
127
128 int main()
129 {
130 auto t1 = clock();
131
132 std::freopen("../tests/subtask3/grader.in.7", "r", stdin);
133 std::freopen("crocodile.out", "w", stdout);
CAPITOLUL 10. IOI 2011 1085
134
135 int ans;
136 read_input();
137
138 auto t2 = clock();
139
140 ans = travel_plan(N,M,R,L,K,P);
141
142 auto t3 = clock();
143
144 if(ans==solution)
145 printf("Correct.\n");
146 else
147 printf("Incorrect. Returned %d, Expected %d.\n",ans,solution);
148
149 auto t4 = clock();
150
151 // reset console output
152 freopen("CON", "w", stdout);
153
154 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
155 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
156 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
157
158 return 0;
159 }
160
161 // -------------- begin grader -----------------
162 /*
163 t2-t1 = 0.92
164 t3-t2 = 0.407
165 t4-t3 = 0
166
167 Process returned 0 (0x0) execution time : 1.405 s
168 Press any key to continue.
169 */
37 head[u]=cnt++;
38 }
39
40 int travel_plan(int N, int M, int R[][2], int L[], int K, int P[])
41 {
42 for (int i=0;i<N;i++){vis[i]=0;head[i]=-1;}
43 for (int i=0;i<M;i++)
44 {
45 add(R[i][0],R[i][1],L[i]);
46 add(R[i][1],R[i][0],L[i]);
47 }
48
49 for (int i=0;i<K;i++)
50 {
51 Q.push(make_pair(0,P[i]));
52 vis[P[i]]=1;
53 }
54
55 while(!Q.empty())
56 {
57 int dis=Q.top().first,u=Q.top().second;Q.pop();
58 if (++vis[u]!=2)continue;
59 if (u==0)return dis;
60 for (int i=head[u];i!=-1;i=a[i].nxt)
61 Q.push(make_pair(dis+a[i].d,a[i].v));
62 }
63
64 return -123; // !!!
65 }
66
67 // -------------- begin grader -----------------
68
69 void read_input()
70 {
71 int i;
72 my_assert(3==scanf("%d %d %d",&N,&M,&K));
73 for(i=0; i<M; i++)
74 my_assert(3==scanf("%d %d %d",&R[i][0],&R[i][1],&L[i]));
75 for(i=0; i<K; i++)
76 my_assert(1==scanf("%d",&P[i]));
77 my_assert(1==scanf("%d",&solution));
78 }
79
80 int main()
81 {
82 auto t1 = clock();
83
84 std::freopen("../tests/subtask3/grader.in.7", "r", stdin);
85 std::freopen("crocodile.out", "w", stdout);
86
87 int ans;
88 read_input();
89
90 auto t2 = clock();
91
92 ans = travel_plan(N,M,R,L,K,P);
93
94 auto t3 = clock();
95
96 if(ans==solution)
97 printf("Correct.\n");
98 else
99 printf("Incorrect. Returned %d, Expected %d.\n",ans,solution);
100
101 auto t4 = clock();
102
103 // reset console output
104 freopen("CON", "w", stdout);
105
106 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
107 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
108 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
109
110 return 0;
111 }
112
CAPITOLUL 10. IOI 2011 1087
64 my_assert(3==scanf("%d %d %d",&N,&M,&K));
65 for(i=0; i<M; i++)
66 my_assert(3==scanf("%d %d %d",&R[i][0],&R[i][1],&L[i]));
67 for(i=0; i<K; i++)
68 my_assert(1==scanf("%d",&P[i]));
69 my_assert(1==scanf("%d",&solution));
70 }
71
72 int main()
73 {
74 auto t1 = clock();
75
76 std::freopen("../tests/subtask3/grader.in.7", "r", stdin);
77 std::freopen("crocodile.out", "w", stdout);
78
79 int ans;
80 read_input();
81
82 auto t2 = clock();
83
84 ans = travel_plan(N,M,R,L,K,P);
85
86 auto t3 = clock();
87
88 if(ans==solution)
89 printf("Correct.\n");
90 else
91 printf("Incorrect. Returned %d, Expected %d.\n",ans,solution);
92
93 auto t4 = clock();
94
95 // reset console output
96 freopen("CON", "w", stdout);
97
98 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
99 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
100 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
101
102 return 0;
103 }
104
105 // -------------- begin grader -----------------
106 /*
107 t2-t1 = 0.906
108 t3-t2 = 5.007
109 t4-t3 = 0
110
111 Process returned 0 (0x0) execution time : 6.023 s
112 Press any key to continue.
113 */
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 10. IOI 2011 1090
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 10. IOI 2011 1091
Implementation details
Limits
CPU time limit: 9 seconds
Note: The collection templates in the C++ Standard Library (STL) can be slow; in parti-
cular, 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 les 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 nd 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 nd the number of cameras
in time O k log N as follows.
We start by placing the camera at the rst 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 nd the rst 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 rst 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 nd
the current bucket of e we can store a pointer from e, but it takes O k to nd 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 rst 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 sucient to obtain full
marks for this problem. However, an inecient 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 10. IOI 2011 1093
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 nd 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.
27 int n, l, m;
28 int x[150010], v[150010];
29 int bnum;
30 int ucnt;
31
32 struct Bucket
33 {
34 int sz;
35 int x[2 * b_size + 1];
36 int num[2 * b_size + 1];
37 int bound[2 * b_size + 1];
38 void calc()
39 {
40 int t = sz;
41 for(int i = sz - 1; i >= 0; i--)
42 {
43 while(t > 0 && x[t - 1] > x[i] + l) t--;
44 if(t == sz)
45 num[i] = 1, bound[i] = x[i] + l;
46 else
47 num[i] = num[t] + 1, bound[i] = bound[t];
48 }
49 }
50
51 void ins(int y)
52 {
53 int p = (int)(upper_bound(x, x + sz, y) - x);
54 sz++;
55 for(int i = sz - 1; i > p; i--)
56 x[i] = x[i - 1];
57 x[p] = y;
58 calc();
59 }
60
61 void del(int y)
62 {
63 int p = (int)(lower_bound(x, x + sz, y) - x);
64 sz--;
65 for(int i = p; i < sz; i++)
66 x[i] = x[i + 1];
67 calc();
68 }
69
70 } b[b_size + 1];
71
72 void init(int n, int l, int x[])
73 {
74 ::n = n;
75 ::l = l;
76
77 for(int i = 0; i < n; i++)
78 ::x[i] = x[i];
79
80 for(int i = 0; i < n; i += b_size)
81 {
82 for(int j = i; j < n && j < i + b_size; j++)
83 {
84 b[bnum].x[b[bnum].sz++] = x[j];
85 }
86
87 b[bnum++].calc();
88 }
89 }
90
91 void rebucket()
92 {
93 int cnt = 0;
94 for(int i = 0; i < bnum; i++)
95 {
96 for(int j = 0; j < b[i].sz; j++)
97 {
98 v[cnt++] = b[i].x[j];
99 }
100 }
101
102 bnum = 0;
CAPITOLUL 10. IOI 2011 1097
179 read_input();
180
181 auto t2= clock();
182
183 init(N,L,X);
184
185 for(i=0; i<M; i++)
186 {
187 ans = update(ii[i],yy[i]);
188 if(ans==sol[i]) continue;
189
190 printf("Incorrect. In %d-th move, answered %d (%d expected).\n",
191 i+1, ans, sol[i]);
192 return 0;
193 }
194
195 auto t3 = clock();
196
197 printf("Correct.\n");
198
199 auto t4 = clock();
200
201 // reset console output
202 freopen("CON", "w", stdout);
203
204 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
205 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
206 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
207
208 return 0;
209 }
210
211 // ------------- end grader ----------------------
212 /*
213 t2-t1 = 0.25
214 t3-t2 = 22.304
215 t4-t3 = 0
216
217 Process returned 0 (0x0) execution time : 22.586 s
218 Press any key to continue.
219 */
32 };
33
34 bool operator < (const iii& a, int b) { return a.x<b; }
35 bool operator < (int a, const iii& b) { return a<b.x; }
36
37 int A[MX], Q;
38
39 vector<iii> D[C];
40
41 void calc_bucket(vector<iii>& v)
42 {
43 for(int n=v.size(), i=n, p=n; i--;)
44 {
45 while(p && v[i].x<v[p-1].x-M) p--;
46
47 if(p==n)
48 v[i].n=1, v[i].y=v[i].x+M;
49 else
50 v[i].n=v[p].n+1, v[i].y=v[p].y;
51 }
52 }
53
54 void init_buckets()
55 {
56 int k=0;
57 for(auto&v:D)
58 {
59 for(auto[x,n,y]:v) X[k++]=x;
60 v.clear();
61 }
62
63 for(int i=0, j=0; i<N;)
64 {
65 D[j].push_back({X[i], 0, 0});
66 if(++i%B==0 || i==N) calc_bucket(D[j++]);
67 }
68 }
69
70 void del(int x)
71 {
72 for(auto&v:D) if(v.size() && v.front().x<=x && x<=v.back().x)
73 {
74 v.erase(lb(v, x));
75 calc_bucket(v);
76 break;
77 }
78 }
79
80 void add(int x)
81 {
82 int p=0, n=N-1;
83 for(auto&v:D)
84 if(!(n-=v.size()) || v.size() && p<=x && x<=(p=v.back().x))
85 {
86 v.insert(lb(v, x), {x, 0, 0});
87 calc_bucket(v);
88 break;
89 }
90 }
91
92 int answer()
93 {
94 int p=0, n=0;
95 for(auto&v:D) if(v.size() && p<=v.back().x)
96 {
97 auto[x,m,y]=*lb(v, p);
98 n+=m, p=y+1;
99 }
100
101 return n;
102 }
103
104 void init(int n, int m, int E[])
105 {
106 N=n, M=m;
107 for(int i=0; i<C; i++)
CAPITOLUL 10. IOI 2011 1100
108 D[i].reserve(B);
109 for(int i=0; i<N; i++)
110 D[i/B].push_back({A[i]=E[i], 0, 0});
111 }
112
113 int update(int n, int x)
114 {
115 if(Q++%B==0) init_buckets();
116 del(A[n]);
117 add(A[n]=x);
118 return answer();
119 }
120
121 // ------------- begin grader ----------------------
122
123 void read_input()
124 {
125 int i;
126 my_assert(3==scanf("%d %d %d",&N,&L,&M));
127
128 for(i=0; i<N; i++)
129 my_assert(1==scanf("%d",&X[i]));
130
131 for(i=0; i<M; i++)
132 my_assert(3==scanf("%d %d %d",&ii[i],&yy[i],&sol[i]));
133 }
134
135 int main()
136 {
137 auto t1 = clock();
138
139 std::freopen("../tests/subtask5/grader.in.20", "r", stdin);
140 std::freopen("elephants.out", "w", stdout);
141
142 int i, ans;
143
144 read_input();
145
146 auto t2= clock();
147
148 init(N,L,X);
149
150 for(i=0; i<M; i++)
151 {
152 ans = update(ii[i],yy[i]);
153 if(ans==sol[i]) continue;
154
155 printf("Incorrect. In %d-th move, answered %d (%d expected).\n",
156 i+1, ans, sol[i]);
157 return 0;
158 }
159
160 auto t3 = clock();
161
162 printf("Correct.\n");
163
164 auto t4 = clock();
165
166 // reset console output
167 freopen("CON", "w", stdout);
168
169 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
170 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
171 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
172
173 return 0;
174 }
175
176 // ------------- end grader ----------------------
177 /*
178 t2-t1 = 0.249
179 t3-t2 = 1.454
180 t4-t3 = 0
181
182 Process returned 0 (0x0) execution time : 1.734 s
183 Press any key to continue.
CAPITOLUL 10. IOI 2011 1101
184 */
10.6 Parrots
Problema 6 - Parrots 100 de puncte
Author: Jittat Fakcharoenphol
Yanee is a bird enthusiast. Since reading about IP over Avian Carriers (IPoAC), she has spent
much of her time training a ock 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 10. IOI 2011 1102
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 gure.
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 specied in the subtask.
The number of times your procedure encode calls the procedure send must not exceed the
limit K specied 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 sequ-
ence 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 10. IOI 2011 1103
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 10. IOI 2011 1104
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 le as static to prevent them from interfering with
variables from other les.
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 rst calls encode with the
given data, and then it calls decode with the output your procedure encode produced. In the
rst 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 shues the data by modifying its procedure shue (in C/C++) or
Shue (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 les 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 nd 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 10. IOI 2011 1105
There are many ways to solve this task. It will be instructive to look at the rst 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 shued 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 rst 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 rst.
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 shued 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 sucient 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 10. IOI 2011 1106
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 dene 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 23 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 i 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 rst byte, for example), and therefore numbers from 0 to 255 are sucient.
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
256 1.47 10
154
without loss of information. There are 256256
261 517
dierent encoded messages
using no more than 261 bytes. This is just more than 256 1.34 10 , the number of dierent
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 dicult.
CAPITOLUL 10. IOI 2011 1107
71 return ans;
72 }
73
74 bool operator <= (BigNum aux)
75 {
76 if( this->size() != aux.size() ) return this->size() < aux.size();
77
78 for(int i = aux.size() - 1 ; i >= 0 ; i--)
79 if( this->digit(i) != aux.digit(i) ) return this->digit(i) < aux.digit(i
);
80
81 return true;
82 }
83
84 bool operator < (BigNum aux)
85 {
86 if( this->size() != aux.size() ) return this->size() < aux.size();
87
88 for(int i = aux.size() - 1 ; i >= 0 ; i--)
89 if( this->digit(i) != aux.digit(i) ) return this->digit(i) < aux.digit(i
);
90
91 return false;
92 }
93
94 private:
95
96 int base;
97
98 vector< int > num;
99 };
100
101 bool hasInit = false;
102
103 BigNum pot[MAXB];
104 BigNum dp[MAXV][MAXL];
105
106 void buildPowers()
107 {
108 pot[0].insert( 1 );
109
110 for(int i = 1 ; i < MAXB ; i++)
111 pot[i] = pot[i - 1] + pot[i - 1];
112 }
113
114 void buildBinomials()
115 {
116 for(int i = 0 ; i < MAXV ; i++)
117 dp[i][0].insert( 1 );
118
119 for(int i = 1 ; i < MAXV ; i++)
120 for(int j = 1 ; j <= i && j < MAXL ; j++)
121 dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1];
122 }
123
124 void encode(int N, int M[])
125 {
126 if( !hasInit )
127 {
128 buildPowers();
129 buildBinomials();
130
131 hasInit = true;
132 }
133
134 BigNum binary;
135
136 for(int i = 0 ; i < N ; i++)
137 for(int j = 0 ; j < 8 ; j++)
138 if( M[i] & (1 << j) ) binary = binary + pot[ 8*i + j ];
139
140 int remainParrots = 5*N;
141
142 BigNum sum;
143
144 for(int i = -1 ; i < 255 ; i++)
CAPITOLUL 10. IOI 2011 1109
145 {
146 int qtdParrots;
147 int qtdNumbers = 256 - i - 1;
148
149 for(qtdParrots = 0 ; qtdParrots <= remainParrots ; qtdParrots++)
150 {
151 BigNum aux = sum;
152 aux = aux+dp[remainParrots-qtdParrots+qtdNumbers-1][qtdNumbers-1];
153
154 if( binary < aux ) break;
155
156 sum = aux;
157 }
158
159 remainParrots -= qtdParrots;
160
161 if( i == -1 ) continue;
162
163 for(int j = 1 ; j <= qtdParrots ; j++)
164 send( i );
165 }
166
167 while( remainParrots > 0 )
168 {
169 send( 255 );
170 remainParrots--;
171 }
172 }
173
174 // --------------- decode --------------------
175
176 int freq[MAXL];
177
178 void decode(int N, int L, int X[])
179 {
180 if( !hasInit )
181 {
182 buildPowers();
183 buildBinomials();
184
185 hasInit = true;
186 }
187
188 BigNum sum;
189
190 int qtd = 5*N - L;
191
192 for(int i = 0 ; i < qtd ; i++)
193 sum = sum + dp[ 5*N - i + 256 ][ 256 ];
194
195 for(int i = 0 ; i < L ; i++)
196 freq[ X[i] ]++;
197
198 int remainParrots = L;
199
200 for(int i = 0 ; i < 255 ; i++)
201 {
202 int qtdNumbers = 256 - i - 1;
203
204 while( freq[i] > 0 )
205 {
206 sum = sum + dp[ remainParrots + qtdNumbers - 1 ][ qtdNumbers-1];
207
208 freq[i]--;
209 remainParrots--;
210 }
211 }
212
213 BigNum cur;
214
215 vector< int > binary;
216
217 for(int i = 8*N - 1 ; i >= 0 ; i--)
218 {
219 BigNum aux = cur + pot[i];
220
CAPITOLUL 10. IOI 2011 1110
373
374 scanf("%d",&p);
375 shuffle(p);
376
377 NN = 0;
378 O = 0;
379 decode(N,M,encoded_message);
380
381 if(!check_output())
382 {
383 printf("Incorrect\n");
384 exit(0);
385 }
386 }
387
388 auto t3 = clock();
389
390 printf("Correct.\n");
391
392 fprintf(stderr,"Ratio: %f\n",(float)M/N);
393
394 auto t4 = clock();
395
396 // reset console output
397 freopen("CON", "w", stdout);
398
399 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
400 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
401 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
402
403 return 0;
404 }
405
406 // ----------------- end grader --------------------
407 /*
408 Correct.
409 Ratio: 5.000000
410 t2-t1 = 0
411 t3-t2 = 1.324
412 t4-t3 = 0
413
414 Process returned 0 (0x0) execution time : 1.894 s
415 Press any key to continue.
416 */
105 {
106 if(a[i] < b[i])
107 {
108 return 1;
109 }
110 return 0;
111 }
112 }
113 return 0;
114 }
115
116 static void calcpt(int n)
117 {
118 pt[0][0] = 1; pt[0][1] = 1;
119 for(int i = 1; i <= n; i++)
120 {
121 mult(pt[i - 1], 256, pt[i]);
122 }
123 }
124
125 static void calcdp(int n)
126 {
127 int i, j;
128 memset(num, 0, sizeof(num) );
129 for(j = 0; j < 256; j++)
130 {
131 d[n - 1][j][0] = d[n - 1][j][1] = 1;
132 }
133
134 for(i = n - 2; i >= 0; i--)
135 {
136 for(j = 255; j >= 0; j--)
137 {
138 adun(d[i + 1][j], d[i][j + 1], d[i][j]);
139 }
140 }
141 }
142
143 void encode(int n, int v[])
144 {
145 int i, j, x, k = 5 * n - 1;
146 calcdp(k);
147 calcpt(n);
148 for(i = 0; i < n; i++)
149 {
150 for(j = 0; j < v[i]; j++)
151 {
152 adun(num, pt[n - i - 1], num);
153 }
154 }
155 adun(num, pt[0], num);
156 x = 0;
157 for(i = 0; i < k; i++)
158 {
159 while( comp(d[i][x], num) )
160 {
161 scad(num, d[i][x]);
162 x++;
163 }
164 send(x);
165 }
166 }
167
168 // --------------- decode --------------------
169
170 void decode(int n, int k, int v[])
171 {
172 int i, x, j;
173 memset(num, 0, sizeof(num) );
174 calcpt(n);
175 calcdp(k);
176 sort(v, v + k);
177 for(j = 0; j < v[i]; j++)
178 {
179 adun(num, d[0][j], num);
180 }
CAPITOLUL 10. IOI 2011 1115
257 }
258 }
259
260 static void random_shuffle()
261 {
262 int i, t, p;
263 for(i=0; i<M-1; i++)
264 {
265 p = rand()%(M-i);
266 t = encoded_message[i];
267 encoded_message[i] = encoded_message[i+p];
268 encoded_message[i+p] = t;
269 }
270 }
271
272 static void shuffle(int method)
273 {
274 if(method==0)
275 sort_message(0);
276 else if(method==1)
277 sort_message(1);
278 else
279 random_shuffle();
280 }
281
282 static void check_encoded_message()
283 {
284 int i;
285 if(M > max_expansion * N)
286 {
287 printf("Encoded message too long.");
288 exit(0);
289 }
290
291 for(i=0; i < M; i++)
292 if((encoded_message[i] < 0) ||
293 (encoded_message[i] > channel_range))
294 {
295 printf("Bad encoded integer\n");
296 exit(0);
297 }
298 }
299
300 static int check_output()
301 {
302 int i;
303
304 if(O!=N)
305 return 0;
306 for(i = 0; i < N; i++)
307 if(message[i] != output_message[i])
308 return 0;
309 return 1;
310 }
311
312 int main()
313 {
314 auto t1 = clock();
315
316 std::freopen("../tests/subtask5/grader.in.7", "r", stdin);
317 //std::freopen("parrots.out", "w", stdout);
318
319 int i,tt,t,p,r;
320 int correct;
321
322 scanf("%d",&tt);
323 scanf("%d %d",&max_expansion,&channel_range);
324
325 scanf("%d",&r);
326 srand(r);
327
328 auto t2 = clock();
329
330 for(t=0; t<tt; t++)
331 {
332 scanf("%d",&N);
CAPITOLUL 10. IOI 2011 1117
IOI 201037
11.1 Cluedo
Problema 1 - Cluedo 100 de puncte
Author: Gordon Cormack (CAN)
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.
1118
CAPITOLUL 11. IOI 2010 1119
Implementation Details
Implementation folder: /home/ioi2010-contestant/cluedo/
To be implemented by contestant: cluedo.c or cluedo.cpp or cluedo.pas
Contestant interface: cluedo.h or cluedo.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 three numbers denoting the murderer, the location and the
weapon.
Expected output for sample grader input: if Solve correctly solves all cases, the output le
will contain OK t where t is the maximum number of calls to Theory used for any case.
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 le.
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 le.
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 xed, 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 mo-
notonic 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 conrming call to Theory was required, so a
total of 20 calls suces.
Here is a Pascal solution that can readily be generalized (the constant, type, and auxiliary
function denitions 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;
21 int m=1,l=1,w=1;
22 while(1)
23 {
24 int r = Theory(m,l,w);
25 if(!r) return ;
26 if(r==1) ++m;
27 if(r==2) ++l;
28 if(r==3) ++w;
29 }
30 }
31
32 // -------------- begin grader ----------------------
33
34 int Theory(int m, int l, int w)
35 {
36 ++cnt;
37 if (m < 1 || m > 6 || l < 1 || l > 10 || w < 1 || w > 6) exit(92);
38
39 if (rand()%2 && m != M) return 1;
40 else
41 if (rand()%2 && l != L) return 2;
42 else
43 if (rand()%2 && w != W) return 3;
44 else
45 if (m != M) return 1;
46 else
47 if (l != L) return 2;
48 else
49 if (w != W) return 3;
50
51 gotit = 1;
52 return 0;
53 }
54
55 int main()
56 {
57 std::freopen("../tests/Subtask1-data/grader.in.1", "r", stdin);
58 //std::freopen("cluedo.out", "w", stdout);
59
60 while (3 == scanf("%d%d%d",&M,&L,&W))
61 {
62 cnt = gotit = 0;
63
64 Solve();
65
66 if (cnt > maxcnt) maxcnt = cnt;
67 if (!gotit)
68 {
69 printf("NO\n");
70 return 91;
71 }
72 }
73
74 printf("OK %d\n",maxcnt);
75
76 return 0;
77 }
78
79 // -------------- end grader ----------------------
14
15 void Solve()
16 {
17 int i=1, j=1, k=1, r;
18 while(1)
19 {
20 r = Theory(i, j, k);
21 if(r==0) return;
22 else if(r==1) i++;
23 else if(r==2) j++;
24 else if(r==3) k++;
25 }
26 }
27
28 // -------------- begin grader ----------------------
29
30 int Theory(int m, int l, int w)
31 {
32 ++cnt;
33 if (m < 1 || m > 6 || l < 1 || l > 10 || w < 1 || w > 6) exit(92);
34
35 if (rand()%2 && m != M) return 1;
36 else
37 if (rand()%2 && l != L) return 2;
38 else
39 if (rand()%2 && w != W) return 3;
40 else
41 if (m != M) return 1;
42 else
43 if (l != L) return 2;
44 else
45 if (w != W) return 3;
46
47 gotit = 1;
48 return 0;
49 }
50
51 int main()
52 {
53 std::freopen("../tests/Subtask1-data/grader.in.1", "r", stdin);
54 //std::freopen("cluedo.out", "w", stdout);
55
56 while (3 == scanf("%d%d%d",&M,&L,&W))
57 {
58 cnt = gotit = 0;
59
60 Solve();
61
62 if (cnt > maxcnt) maxcnt = cnt;
63 if (!gotit)
64 {
65 printf("NO\n");
66 return 91;
67 }
68 }
69
70 printf("OK %d\n",maxcnt);
71
72 return 0;
73 }
74 // -------------- end grader ----------------------
12
13 static int M,L,W,gotit,cnt,maxcnt;
14
15 #include <bits/stdc++.h>
16
17 void Solve(void)
18 {
19 int i[] = {1, 1, 1};
20 while(true)
21 {
22 int r = Theory(i[0], i[1], i[2]);
23 if(r == 0) return;
24 i[r - 1]++;
25 }
26 }
27
28 // -------------- begin grader ----------------------
29
30 int Theory(int m, int l, int w)
31 {
32 ++cnt;
33 if (m < 1 || m > 6 || l < 1 || l > 10 || w < 1 || w > 6) exit(92);
34
35 if (rand()%2 && m != M) return 1;
36 else
37 if (rand()%2 && l != L) return 2;
38 else
39 if (rand()%2 && w != W) return 3;
40 else
41 if (m != M) return 1;
42 else
43 if (l != L) return 2;
44 else
45 if (w != W) return 3;
46
47 gotit = 1;
48 return 0;
49 }
50
51 int main()
52 {
53 std::freopen("../tests/Subtask1-data/grader.in.1", "r", stdin);
54 //std::freopen("cluedo.out", "w", stdout);
55
56 while (3 == scanf("%d%d%d",&M,&L,&W))
57 {
58 cnt = gotit = 0;
59
60 Solve();
61
62 if (cnt > maxcnt) maxcnt = cnt;
63 if (!gotit)
64 {
65 printf("NO\n");
66 return 91;
67 }
68 }
69
70 printf("OK %d\n",maxcnt);
71
72 return 0;
73 }
74
75 // -------------- end grader ----------------------
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 rst 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 (rst 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 le contains several lines, each containing N and Jill's number.
Expected output for sample grader input: the grader will create les grader.out.1
grader.out.2 etc.
CAPITOLUL 11. IOI 2010 1125
` 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 α
This problem is an interesting variant of the well-known guessing game Higher-Lower, also featured
in the demonstration task Guess.
Higher-Lower is eciently 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 dierently, 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 rst 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 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 rst 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 11. IOI 2010 1131
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 */
15 int HC(int N)
16 {
17 int L = 1, R = N, prv, nxt, t, W = log(3 * N) / log(2);
18 while (L < R)
19 {
20 if (R == 2)
21 {
22 Guess(1);
23 return Guess(2) < 0 ? 1 : 2;
24 }
25 int cut = W & 1 ? (2 << W - 2) / 3 + 1 : (2 << W - 2) / 3 + 2;
26 nxt = R == N ? cut + cal(R - cut) : cut + cut - 1;
27 prv = cut + cut - nxt;
28 Guess(prv);
29 t = Guess(nxt);
30 if (t == -1) R = prv + nxt - 1 >> 1;
31 if (t == 0) return prv + nxt >> 1;
32 if (t == 1)
33 {
34 L = prv + nxt + 2 >> 1;
35 prv = nxt;
36 while (L < R)
37 {
38 nxt = (L + R >> 1 << 1) - prv;
39 if (nxt == prv) nxt++;
40 if (nxt < 1) nxt = 1;
41 if (nxt > N) nxt = N;
42 t = Guess(nxt);
43 if (t == -1)
44 {
45 if (prv < nxt) R = nxt + prv - 1 >> 1;
46 else L = nxt + prv + 2 >> 1;
47 }
48 if (t == 0) return nxt + prv >> 1;
49 if (t == 1)
50 {
51 if (prv < nxt) L = nxt + prv + 2 >> 1;
52 else R = nxt + prv - 1 >> 1;
53 }
54 prv = nxt;
55 }
56 }
57 W -= 2;
58 }
59 return L;
60 }
61
62 // ----------------------- begin grader --------------------
63
64 static int moves, TT, NN, prev = -1;
65 int Guess(int x){
66 int r;
67 if (prev == -1 || abs(x-TT) == abs(prev-TT)) r = 0;
68 else if (abs(x-TT) > abs(prev-TT)) r = -1;
69 else r = 1;
70 prev = x;
71 if (x < 1 || x > NN) exit(92);
72 moves++;
73 return r;
74 }
75
76 int main()
77 {
78 //freopen("../tests/Subtask1-data/grader.in.1", "r", stdin);
79 freopen("../tests/Subtask4-data/grader.in.2", "r", stdin);
80
81 //freopen("hottercolder.out", "w", stdout);
82
83 int n=0,i,t,OK=0,sub1=0,sub2=0,sub3=0;
84 double worst = 999999;
85 while (2 == scanf("%d%d",&NN,&TT))
86 {
87 if (NN > n) n = NN;
88 prev = -1;
89 moves = 0;
90 int h = HC(NN);
CAPITOLUL 11. IOI 2010 1133
91 if (h != TT)
92 {
93 exit(91);
94 }
95 int W = floor(0.00001+log(3*NN)/log(2));
96 double alpha = 2 - (double)moves/W;
97 if (alpha < worst) worst = alpha;
98 // 1 means failure
99 if ( NN <= 500 && moves > 500 ) exit(93);
100 if ( NN <= 500 && moves > 18 ) sub2=1;
101 if ( NN <= 500 && moves > 16 ) sub3=1;
102 OK++;
103 }
104 if (!sub1) printf("OK 1\n");
105 if (!sub2) printf("OK 2\n");
106 if (!sub3) printf("OK 3\n");
107 if (worst > 0) printf("OK 4 alpha %0.2lf\n",worst);
108 return 0;
109 }
110 // ----------------------- end grader --------------------
111 /*
112 OK 1
113 OK 2
114 OK 3
115 OK 4 alpha 1.00
116
117 Process returned 0 (0x0) execution time : 2.979 s
118 Press any key to continue.
119 */
44 }
45
46 vi soFar, guess;
47 pi posi;
48 int N;
49
50 bool tri(int x)
51 {
52 guess.pb(Guess(x));
53 if (guess.bk == 0)
54 {
55 if (sz(soFar) && soFar.bk != x)
56 posi.f = posi.s = (soFar.bk+x)/2;
57 }
58 else
59 {
60 if (guess.bk == -1)
61 {
62 if (x < soFar.bk)
63 {
64 ckmax(posi.f,(soFar.bk+x)/2+1);
65 }
66 else
67 {
68 ckmin(posi.s,(soFar.bk+x-1)/2);
69 }
70 }
71 else
72 {
73 if (x < soFar.bk)
74 {
75 ckmin(posi.s,(soFar.bk+x-1)/2);
76 }
77 else
78 {
79 ckmax(posi.f,(soFar.bk+x)/2+1);
80 }
81 }
82 }
83 soFar.pb(x); assert(posi.f <= posi.s);
84 return posi.f == posi.s;
85 }
86
87 int binSearch()
88 {
89 while (1)
90 {
91 int des = posi.f+posi.s-soFar.bk;
92 ckmax(des,1); ckmin(des,N);
93 if (tri(des)) return posi.f;
94 }
95 }
96
97 int HC(int _N)
98 {
99 N = _N;
100 guess.clear(), soFar.clear(); posi = {1,N};
101 if (N == 1) return 1;
102 int m = N/2+1;
103 int a = m-1, b = m;
104 tri(a); if (tri(b)) return posi.f;
105 if (posi.f == 1)
106 {
107 while (1)
108 {
109 if (soFar.bk <= 3)
110 {
111 assert(tri(1));
112 return posi.f;
113 }
114 if (soFar.bk <= 7)
115 {
116 tri(1);
117 return binSearch();
118 }
119 vi one = {3}, two = {7};
CAPITOLUL 11. IOI 2010 1135
196 }
197 }
198
199 // ----------------------- begin grader --------------------
200
201 static int moves, TT, NN, prevv = -1;
202
203 int Guess(int x)
204 {
205 int r;
206 if (prevv == -1 || abs(x-TT) == abs(prevv-TT)) r = 0;
207 else
208 if (abs(x-TT) > abs(prevv-TT)) r = -1;
209 else r = 1;
210
211 prevv = x;
212 if (x < 1 || x > NN) exit(92);
213 moves++;
214 return r;
215 }
216
217 int main()
218 {
219 //freopen("../tests/Subtask1-data/grader.in.1", "r", stdin);
220 freopen("../tests/Subtask4-data/grader.in.2", "r", stdin);
221
222 //freopen("hottercolder.out", "w", stdout);
223
224 int n=0,i,t,OK=0,sub1=0,sub2=0,sub3=0;
225 double worst = 999999;
226 while (2 == scanf("%d%d",&NN,&TT))
227 {
228 if (NN > n) n = NN;
229 prevv = -1;
230 moves = 0;
231 int h = HC(NN);
232 if (h != TT)
233 {
234 exit(91);
235 }
236 int W = floor(0.00001+log(3*NN)/log(2));
237 double alpha = 2 - (double)moves/W;
238 if (alpha < worst) worst = alpha;
239 // 1 means failure
240 if ( NN <= 500 && moves > 500 ) exit(93);
241 if ( NN <= 500 && moves > 18 ) sub2=1;
242 if ( NN <= 500 && moves > 16 ) sub3=1;
243 OK++;
244 }
245 if (!sub1) printf("OK 1\n");
246 if (!sub2) printf("OK 2\n");
247 if (!sub3) printf("OK 3\n");
248 if (worst > 0) printf("OK 4 alpha %0.2lf\n",worst);
249 return 0;
250 }
251 // ----------------------- end grader --------------------
252 /*
253 OK 1
254 OK 2
255 OK 3
256 OK 4 alpha 1.00
257
258 Process returned 0 (0x0) execution time : 22.549 s
259 Press any key to continue.
260 */
CAPITOLUL 11. IOI 2010 1137
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 dened 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 11. IOI 2010 1138
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 suce 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 lling/emptying the array to be sorted. But these improvements
do not aect 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 oset of the nal rectangle is known [O N possibilities]. Then scan across the row,
using some ecient 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 veried 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 nd the minimum value for which
the answer is "yes".
CAPITOLUL 11. IOI 2010 1139
119
120 auto t2 = clock();
121
122 ans = rectangle(R,C,H,W,Q);
123
124 auto t3 = clock();
125
126 printf("%d\n",ans);
127
128
129 auto t4 = clock();
130
131 // reset console output
132 freopen("CON", "w", stdout);
133
134 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
135 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
136 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
137
138 return 0;
139 }
140
141 // ------------ end grader ---------------
142 /*
143 t2-t1 = 3.828
144 t3-t2 = 7.109
145 t4-t3 = 0
146
147 Process returned 0 (0x0) execution time : 11.109 s
148 Press any key to continue.
149 */
42 {
43 if(target < (H*W)/2)
44 return false;
45 F0R(i, R)
46 F0R(j ,C)
47 {
48 pre[i][j]=(rect[i][j]==target ? 0:(rect[i][j]<target ? -1:1))+
49 (i==0 ? 0:pre[i-1][j]) + (j==0 ? 0:pre[i][j-1]) -
50 ((i==0||j==0) ? 0 : pre[i-1][j-1]);
51
52 if(i >= H-1 && j >= W-1)
53 {
54 int tmp = pre[i][j] - (i==H-1 ? 0 : pre[i-H][j]) -
55 (j==W-1 ? 0 : pre[i][j-W]) +
56 ((i==H-1||j==W-1) ? 0 : pre[i-H][j-W]);
57
58 if((tmp < 0) || (tmp == 0 && in(target)))
59 {
60 return true;
61 }
62 }
63 }
64 return false;
65 }
66
67 int rectangle(int R, int C, int H, int W, int( * Q)[3001])
68 {
69 F0R(i, R)
70 F0R(j, C)
71 rect[i][j] = Q[i][j]-1;
72 F0R(i, R)
73 F0R(j, C)
74 Lookup[rect[i][j]] = mp(i, j);
75 int lo = 0, hi = R*C - 1, mid;
76 while(hi > lo + 1)
77 {
78 mid = (hi + lo)/2;
79 if(bs(R, C, H, W, mid))
80 hi = mid;
81 else
82 lo = mid;
83 }
84 return hi+1;
85 }
86
87 // ------------ begin grader ---------------
88
89 static int R,C,H,W,Q[3001][3001],i,j,ans;
90
91 int main()
92 {
93 auto t1 = clock();
94
95 freopen("../tests/Subtask5-data/grader.in.3-5", "r", stdin);
96 freopen("quality.out", "w", stdout);
97
98 scanf("%d%d%d%d",&R,&C,&H,&W);
99 for (i=0;i<R;i++)
100 for (j=0;j<C;j++) scanf("%d",&Q[i][j]);
101
102 auto t2 = clock();
103
104 ans = rectangle(R,C,H,W,Q);
105
106 auto t3 = clock();
107
108 printf("%d\n",ans);
109
110
111 auto t4 = clock();
112
113 // reset console output
114 freopen("CON", "w", stdout);
115
116 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
117 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
CAPITOLUL 11. IOI 2010 1144
118 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
119
120 return 0;
121 }
122
123 // ------------ end grader ---------------
124 /*
125 t2-t1 = 3.921
126 t3-t2 = 8.5
127 t4-t3 = 0
128
129 Process returned 0 (0x0) execution time : 12.578 s
130 Press any key to continue.
131 */
11.4 Languages
Problema 4 - Languages 100 de puncte
Author: Gordon Cormack (CAN)
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 11. IOI 2010 1145
The grading server calls excerpt(E) 10 000 times, once for each excerpt in its input le. 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 dened
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-specic
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 nhạc và Thá»i
trang) là chương tr
55. ISO 3166-2:GU ni akoole ninu ISO 3166-2 , apa opagun ISO 3166 ti International Organi-
zation for Stan
56. ä¸å¡å§æ¯å
ï¼ ä¿æ ï¼ ÐижнекаÌмÑк ï¼ éé¼èª ï¼
ТүбÉн Ðама/Tübän Kama ï¼æ¯ ä¿ç¾
æ¯ éé¼æ¯å¦å
±åå æ-
±åé¨çä¸ååå¸ï¼ä½æ¼ å¡é¦¬æ²³ å岸ã 2002å¹´ 人å£22
The sample input le 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 rst paragraph
of an article chosen at random from the corresponding Wikipedia edition. Each line of the le
contains:
The two-letter ISO code for the Wikipedia language edition;
100 numbers between 1 and 65 535, representing the rst 100 symbols, in sequence, of the
rst 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 ocial grader uses 10 000 dierent excerpts, selected in the same way from the same 56
Wikipedia editions. However, the grader assigns a dierent number between 0 and 55 to each
language, and a dierent 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 specied
for each of the 10 000 examples, the sample grader will output OKalpha where alpha is the
accuracy.
CAPITOLUL 11. IOI 2010 1146
The nature of this problem is innovative within the IOI. Its purpose is to bring the eld of
information retrieval under the attention. This problem is discussed in detail in the book Infor-
mation Retrieval: Implementing and Evaluating Search Engines by S. Büttcher, 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 oered, the
variability between excerpts from the same language play a negligible role. It has been conrmed
that the statistical resemblance between the provided test input and the ocial 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 specic (personal) language knowledge into a solution.
There are many approaches possible. Rocchio's method, which was informally described in the
task description, suces 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.
26 {
27 if(pos == 0) t1 = p;
28 else t2 |= (1ll << (16 * (4 - pos))) * p;
29 }
30 };
31
32 bool operator<(WD a, WD b)
33 {
34 return a.t1 != b.t1 ? (a.t1 > b.t1) : (a.t2 > b.t2);
35 }
36
37 map<WD,int> mp;
38 const int l = 5;
39
40 void excerpt(int *E)
41 {
42 int cnt[105] = {};
43 vector<WD> v;
44 for (int i=0; i<96; i++)
45 {
46 WD px;
47 px.init();
48 for (int j=0; j<l; j++)
49 {
50 px.addwd(E[i+j],j);
51 }
52
53 map<WD,int> ::iterator it = mp.lower_bound(px);
54
55 if(it != mp.end()) cnt[( *it).second] += 100;
56 it = mp.upper_bound(px);
57 if(it != mp.end()) cnt[( *it).second] += 85;
58 if(it != mp.begin()) cnt[( *--it).second] += 100;
59 v.push_back(px);
60 }
61
62 int mv = (int)(max_element(cnt,cnt+56) - cnt);
63 int t = language(mv);
64 for (int i=0; i<v.size(); i++)
65 {
66 mp[v[i]] = t;
67 }
68 }
69
70 // ------------ begin grader --------------------
71
72 #define N 100
73
74 static char lang[20], lan[100][20];
75 static int lnum, i,j,k,n,nl, uni[N], rightt, tot;
76
77 int language(int L)
78 {
79 if (L < 0 || L >= 56) exit(92);
80 rightt += (L == lnum);
81 tot++;
82 return lnum;
83 }
84
85 int main()
86 {
87 auto t1 = clock();
88
89 freopen("../tests/Subtask1-data/grader.in.1", "r", stdin);
90 freopen("language.out", "w", stdout);
91
92 auto t2 = clock();
93
94 for (n=0; 1 == scanf("%s",lang); n++)
95 {
96 for (i=0;i<nl && strcmp(lang,lan[i]);i++);
97 strcpy(lan[i],lang);
98 if (i == nl) {
99 nl++;
100 }
101 lnum = i;
CAPITOLUL 11. IOI 2010 1150
32
33 int best = 0;
34 double best_sim = 0;
35 FOR(i, 0, LANGS)
36 {
37 double sim = 0;
38 FOR(j, 0, SZ - 3)
39 {
40 sim += hyperb(freq[i][qu[j]]) * 138;
41 sim += hyperb(freq[i][tr[j]]) * 60;
42 sim += hyperb(freq[i][bi[j]]) * 97;
43 sim += hyperb(freq[i][si[j]]) * 1;
44 }
45 sim /= log(cnt[i] + 1);
46
47 if (sim > best_sim) best = i, best_sim = sim;
48 }
49
50 int ans = language(best);
51 cnt[ans]++;
52 FOR(i, 0, SZ - 3)
53 {
54 freq[ans][qu[i]]++;
55 freq[ans][tr[i]]++;
56 freq[ans][bi[i]]++;
57 freq[ans][si[i]]++;
58 }
59 }
60
61 // ------------ begin grader --------------------
62
63 #define N 100
64
65 static char lang[20], lan[100][20];
66 static int lnum, i,j,k,n,nl, uni[N], rightt, tot;
67
68 int language(int L)
69 {
70 if (L < 0 || L >= 56) exit(92);
71 rightt += (L == lnum);
72 tot++;
73 return lnum;
74 }
75
76 int main()
77 {
78 auto t1 = clock();
79
80 freopen("../tests/Subtask1-data/grader.in.1", "r", stdin);
81 freopen("language.out", "w", stdout);
82
83 auto t2 = clock();
84
85 for (n=0; 1 == scanf("%s",lang); n++)
86 {
87 for (i=0;i<nl && strcmp(lang,lan[i]);i++);
88 strcpy(lan[i],lang);
89 if (i == nl)
90 {
91 nl++;
92 }
93 lnum = i;
94 for (i=0;i<N;i++) scanf("%d,",&uni[i]);
95 scanf("%*[^\n]");
96 excerpt(uni);
97 }
98
99 auto t3 = clock();
100
101 printf("OK %0.2lf%%\n",100.0*rightt/tot);
102
103 auto t4 = clock();
104
105 // reset console output
106 freopen("CON", "w", stdout);
107
CAPITOLUL 11. IOI 2010 1154
11.5 Memory
Problema 5 - Memory 100 de puncte
Author: Gordon Cormack (CAN)
This was intended to be another very easy task, though slightly more dicult 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) suces. This can be programmed with two nested for-loops, and it
solves Subtask 1.
CAPITOLUL 11. IOI 2010 1156
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 rst turn all cards, in pairs, to discover and
record where all the letters are, without caring about turning up equal pairs. In this rst 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 ip them, in sequence, to obtain all remaining candies.
The rst 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 identied in the rst 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 denitions
could be eliminated, but they document the relevant concepts nicely):
33 is_up[C] = 1;
34 up[moves%2] = C;
35 moves++;
36 if (moves%2 == 0)
37 {
38 c0 = card[ up[0] ] - ’A’;
39 c1 = card[ up[1] ] - ’A’;
40 if (c0==c1 && !candy[c0])
41 {
42 candy[c0] = 1;
43 ++candies;
44 }
45 is_up[ up[0] ] = is_up[ up[1] ] = 0;
46 }
47 return card[C];
48 }
49
50 void playgame()
51 {
52 int i;
53 for (i=1;i<=50;i++)
54 {
55 card[i] = getchar();
56 }
57 moves = candies = 0;
58 play();
59 if (candies != 25)
60 {
61 exit(91);
62 }
63 }
64
65 int main()
66 {
67 std::freopen("../tests/Subtask1-data/grader.in.99", "r", stdin);
68 //std::freopen("cluedo.out", "w", stdout);
69
70 playgame();
71 printf("OK %d\n",moves);
72 return 0;
73 }
74 // ------------ end grader --------------------
31 is_up[C] = 1;
32 up[moves%2] = C;
33 moves++;
34 if (moves%2 == 0)
35 {
36 c0 = card[ up[0] ] - ’A’;
37 c1 = card[ up[1] ] - ’A’;
38 if (c0==c1 && !candy[c0])
39 {
40 candy[c0] = 1;
41 ++candies;
42 }
43 is_up[ up[0] ] = is_up[ up[1] ] = 0;
44 }
45 return card[C];
46 }
47
48 void playgame()
49 {
50 int i;
51 for (i=1;i<=50;i++)
52 {
53 card[i] = getchar();
54 }
55 moves = candies = 0;
56 play();
57 if (candies != 25)
58 {
59 exit(91);
60 }
61 }
62
63 int main()
64 {
65 std::freopen("../tests/Subtask1-data/grader.in.98", "r", stdin);
66 //std::freopen("cluedo.out", "w", stdout);
67
68 playgame();
69 printf("OK %d\n",moves);
70 return 0;
71 }
72
73 // ------------ end grader --------------------
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 rst line of the input le 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 D i 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 le.
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 le.
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 rst think because of the need to handle
specic 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 suces 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 11. IOI 2010 1163
71 int main()
72 {
73 auto t1 = clock();
74
75 std::freopen("../tests/Subtask4-data/grader.in.52-4", "r", stdin);
76 std::freopen("traffic.out", "w", stdout);
77
78 int i;
79 scanf("%d",&N);
80 for (i=0;i<N;i++) scanf("%d",&P[i]);
81 for (i=0;i<N-1;i++) scanf("%d%d",&S[i],&D[i]);
82
83 auto t2 = clock();
84
85 int r = LocateCentre(N,P,S,D);
86
87 auto t3 = clock();
88
89 printf("%d\n",r);
90
91 auto t4 = clock();
92
93 // reset console output
94 freopen("CON", "w", stdout);
95
96 std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
97 std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
98 std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
99
100 return 0;
101 }
102
103 // ------------- end grader -----------------------
104 /*
105 t2-t1 = 1.031
106 t3-t2 = 1.438
107 t4-t3 = 0
108
109 Process returned 0 (0x0) execution time : 3.406 s
110 Press any key to continue.
111 */
11.7 Maze
Problema 7 - Maze 100 de puncte
Authors: Monika Steinová (CHE/SWK), Michal Forisek (SWK)
CAPITOLUL 11. IOI 2010 1168
##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 eld is transformed into a maze by crushing squares occupied by corn. One crushed square
(the entrance) must be on the edge of the eld. 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 identied 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.
11.8 Saveit
Problema 8 - Saveit 100 de puncte
Author: Mihai P tra³cu (ROM)
CAPITOLUL 11. IOI 2010 1171
Example
As an example, consider the diagram on the right.
It shows ve cities (N=5) connected by seven aircraft
(P=7). Cities 0, 1 and 2 are hubs (H=3). One hop
is needed to ship a package between hub 0 and city 3,
whereas 2 hops are needed to ship a package between
hub 2 and city 3. The data for this example are in grader.in.1.
The entries in the following table are all d-values that decode must deliver by calling
hops(h,c,d):
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 eciency matters.
However, in this case it is not execution time or memory usage but rather communication eciency:
how to represent some complex data in as few bits as possible, without losing information.
This dierence 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, nd a way to encode adjacency information about Xedef's
package transportation network. Second, to transmit that information with communication e-
ciency.
Briey 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 11. IOI 2010 1173
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 eciency 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.
40 }
41 return bits[curbit++];
42 }
43
44 void hops(int a, int b, int d)
45 {
46 if (h[a][b] != d)
47 {
48 exit(92);
49 }
50 h[a][b] = -1;
51 hcnt++;
52 }
53
54 // -------------- encoder --------------------
55
56 int const nmax = 1000;
57 int const kmax = 36; // = 40 ... !!!
58
59 using ll = long long;
60
61 std::vector<int> g[1 + nmax];
62
63 std::vector<int> bfs(int n, int node)
64 {
65 std::vector<int> dist(n);
66 std::queue<int> q;
67 q.push(node);
68 dist[node] = 1;
69 while(0 < q.size())
70 {
71 int node = q.front();
72 q.pop();
73 for(int h = 0; h < g[node].size(); h++)
74 {
75 int to = g[node][h];
76 if(dist[to] == 0)
77 {
78 dist[to] = dist[node] + 1;
79 q.push(to);
80 }
81 }
82 }
83 for(int i = 0; i < n; i++)
84 dist[i]--;
85 return dist;
86 }
87
88 std::vector<int> dist[1 + kmax];
89 int far[1 + nmax];
90
91 int const necessary = 35 / 5 * 8;
92
93 void push(ll number, int bits)
94 {
95 for(int i = 0; i < bits; i++)
96 encode_bit(0 < (number & (1LL << i)));
97 }
98
99 void encode(int n, int k, int m, int *v1, int *v2)
100 {
101 for(int i = 0; i < m; i++)
102 {
103 int x = v1[i];
104 int y = v2[i];
105 g[x].push_back(y);
106 g[y].push_back(x);
107 }
108
109 for(int i = 0; i < k; i++)
110 dist[i] = bfs(n, i);
111
112 for(int i = 1;i < n; i++)
113 {
114 for(int h = 0; h < g[i].size(); h++)
115 {
CAPITOLUL 11. IOI 2010 1175
24 bits[nb++] = bit;
25 }
26
27 int decode_bit()
28 {
29 if (curbit >= nb)
30 {
31 exit(92);
32 }
33 return bits[curbit++];
34 }
35
36 void hops(int a, int b, int d)
37 {
38 if (h[a][b] != d)
39 {
40 exit(92);
41 }
42 h[a][b] = -1;
43 hcnt++;
44 }
45
46 // -------------- encoder --------------------
47
48 int dst[44][1010];
49 vector<int> g[1010];
50 int par[1010];
51 int vis[1010];
52
53 void dfs(int v = 1)
54 {
55 vis[v] = 1;
56 for(auto i : g[v]) if(!vis[i])
57 {
58 par[i] = v; dfs(i);
59 }
60 }
61
62 void bfs(int st)
63 {
64 dst[st][st] = 0;
65 queue<int> q; q.push(st);
66 while(q.size())
67 {
68 int now = q.front(); q.pop();
69 for(auto nxt : g[now]) if(dst[st][nxt] == -1)
70 {
71 dst[st][nxt] = dst[st][now] + 1;
72 q.push(nxt);
73 }
74 }
75 }
76
77 void encode(int N, int H, int M, int *v1, int *v2)
78 {
79 int n = N, m = M, h = H;
80 for(int i=0; i<m; i++)
81 {
82 int s = v1[i] + 1, e = v2[i] + 1;
83 g[s].push_back(e); g[e].push_back(s);
84 }
85
86 dfs();
87
88 for(int i=2; i<=n; i++)
89 {
90 for(int k=0; k<10; k++) encode_bit(!!(par[i] & (1 << k)));
91 }
92
93 memset(dst, -1, sizeof dst);
94 for(int i=1; i<=h; i++) bfs(i);
95
96 for(int i=1; i<=h; i++) for(int j=2; j<=n; j+=5)
97 {
98 int t = 0;
99 for(int k=0; k<5; k++)
CAPITOLUL 11. IOI 2010 1178
100 {
101 int now = dst[i][j+k] - dst[i][par[j+k]] + 1;
102 if(j + k > n) now = 0;
103 t = t * 3 + now;
104 }
105
106 for(int k=0; k<8; k++)
107 encode_bit(!!(t & (1 << k)));
108 }
109 }
110
111 // -------------- decoder --------------------
112
113 /*
114 dst[i][j] - dst[i][par[j]]
115 1 : 0
116 -1 : 11
117 0 : 10
118 */
119
120 int p[1010];
121 int mm[44][1010];
122 int chk[1010];
123 int ans[44][1010];
124
125 void go(int hh, int v)
126 {
127 if(v == 1) return;
128 if(!chk[p[v]]) go(hh, p[v]);
129 ans[hh][v] = ans[hh][p[v]] + mm[hh][v];
130 chk[v] = 1;
131 }
132
133 void decode(int N, int H)
134 {
135 int n = N, h = H;
136 for(int i=2; i<=n; i++)
137 {
138 for(int j=0; j<10; j++) p[i] += (decode_bit() << j);
139 }
140
141 for(int i=1; i<=h; i++) for(int j=2; j<=n; j+=5)
142 {
143 int ret = 0;
144 for(int k=0; k<8; k++)
145 ret += (decode_bit() << k);
146 for(int k=4; k>=0; k--)
147 {
148 mm[i][j+k] = ret % 3 - 1;
149 ret /= 3;
150 }
151 }
152
153 for(int i=1; i<=h; i++)
154 {
155 memset(chk, 0, sizeof chk);
156 chk[1] = 1;
157 for(int j=2; j<=n; j++) go(i, j);
158 }
159
160 for(int i=1; i<=h; i++)
161 for(int j=1; j<=n; j++)
162 hops(i-1, j-1, ans[i][j] - ans[i][i]);
163 }
164
165 // ----------------- begin grader ------------------------
166
167 /* and here is the driver */
168
169 int main(int argc, char **argv)
170 {
171 std::freopen("../tests/Subtask1-data/grader.in.25a", "r", stdin);
172
173 //std::freopen("saveit.out", "w", stdout);
174
175 assert(3 == scanf("%i%i%i", &nv, &ne, &c));
CAPITOLUL 11. IOI 2010 1179
176
177 FOR(i,ne)
178 assert(2 == scanf("%i%i", v1+i, v2+i));
179
180 for (int i=0;i<c;i++)
181 for (int j=0;j<nv;j++)
182 scanf("%d",&h[i][j]);
183
184 encode(nv, c, ne, v1, v2);
185
186 decode(nv, c);
187
188 if (hcnt != c*nv)
189 {
190 exit(92);
191 }
192
193 printf("%s 1\n",nb<=16000000?"OK":"NO");
194 printf("%s 2\n",nb<=360000?"OK":"NO");
195 printf("%s 3\n",nb<=80000?"OK":"NO");
196 printf("%s 4\n",nb<=70000?"OK":"NO");
197 }
198
199 // ----------------- end grader ------------------------
200 /*
201 OK 1
202 OK 2
203 OK 3
204 OK 4
205
206 Process returned 0 (0x0) execution time : 0.398 s
207 Press any key to continue.
208 */
A.1 ...
A.1.1 ...
1181
Anexa B
Formule - utile
B.1 ...
B.1.1 ...
1182
Glosar
1183
GLOSAR 1184
[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
[5] Bell D., Perr M.; Java for Students, Second Edition, Prentice Hall, 1999
[7] Cerchez, E., erban, M.; Informatic - manual pentru clasa a X-a., Ed. Polirom, 2000
[8] Cerchez, E.; Informatic - Culegere de probleme pentru liceu, Ed. Polirom, 2002
[9] Cerchez, E., erban, M.; Programarea în limbajul C/C++ pentru liceu, Ed. Polirom, 2005
[10] Cori, R.; Lévy, J.J.; Algorithmes et Programmation, Polycopié, version 1.6;
http://w3.edu.polytechnique.fr/informatique/
[11] Cormen, T.H., Leiserson C.E., Rivest, R.L.; Introducere în Algoritmi, Ed Agora, 2000
[12] Cormen, T.H., Leiserson C.E., Rivest, R.L.; Pseudo-Code Language, 1994
[13] Cristea, V.; Giumale, C.; Kalisz, E.; Paunoiu, Al.; Limbajul C standard, Ed. Teora, Bucure³ti,
1992
[16] Giumale C., Negreanu L., C linoiu S.; Proiectarea ³i analiza algoritmilor. Algoritmi de sortare,
Ed. All, 1997
[18] Knuth, D.E.; Arta program rii calculatoarelor, vol. 1: Algoritmi fundamentali, Ed. Teora,
1999.
[19] Knuth, D.E.; Arta programarii calculatoarelor, vol. 2: Algoritmi seminumerici, Ed. Teora,
2000.
[20] Knuth, D.E.; Arta programarii calculatoarelor, vol. 3: Sortare ³i c utare, Ed. Teora, 2001.
[21] Knuth, D.E.; The art of computer programming, vol. 4A: Combinatorial algorithms, Part 1,
Addison Wesley, 2011.
[22] Lambert,K. A., Osborne,M.; Java. A Framework for Programming and Problem Solving,
PWS Publishing, 1999
[24] Livovschi, L.; Georgescu H.; Analiza ³i sinteza algoritmilor. Ed. Enciclopedic , Bucure³ti,
1986.
1186
BIBLIOGRAFIE 1187
[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
[35] Tomescu, I.; Probleme de combinatoric ³i teoria grafurilor, Editura Didactic ³i Pedagogic ,
Bucure³ti, 1981
[36] Tomescu, I.; Leu, A.; Matematic aplicat în tehnica de calcul, Editura Didactic ³i Pedago-
gic , Bucure³ti, 1982
[37] Tudor, S.; Informatic - prolul real intensiv, varianta C++; Editura L&S, Bucure³ti, 2004
[38] Tudor, S.; Hutanu, V,; Informatic intensiv; Editura L&S, Bucure³ti, 2006
[40] Vi³inescu, R.; Vi³inescu, V.; Programare dinamic - teorie ³i aplicaµii; GInfo nr. 15/4 2005
[41] Vlada, M.; Conceptul de algoritm - abordare modern , GInfo, 13/2,3 2003
[43] Vlada, M.; Gândirea Algoritmic - O Filosoe Modern a Matematicii ³i Informaticii, CNIV-
2003, Editura Universit µii din Bucure³ti, 2003
[44] Weis, M.A.; Data structures and Algorithm Analysis, Ed. The Benjamin/Cummings Pu-
blishing Company. Inc., Redwoods City, California, 1995.
[46] Wirth N.; Algorithms + Data Structures = Programs, Prentice Hall, Inc 1976
1189