V okolí reaktoru vraj nejak stúpala radiácia, a tak každý intern vyfasoval jeden Geigerov-Müllerov počítač a poďho do terénu.
A ozaj, ony tie merania vyšli nejak divne. Ale to je určite len nejaká fluktuácia chalani, do reportu to tak nepíšte. Trošku to upravte, tak žeby dobre bolo, a ono to určite samo časom prejde.
Je $a$ internov, každý spravil presne $b$ meraní. Čísla $a$ a $b$ sú obe nepárne.
Medián všetkých meraní je hodnota, ktorá by bola uprostred, keby sme ich všetky usporiadali podľa veľkosti. Do reportu by sme potrebovali napísať také merania, ktorých medián bude presne $m$.
Každý intern môže klamať, a to tak, že prepíše nejaké svoje merania na ľubovolné hodnoty. Koľko najmenej internov musí v reporte klamať?
(Každý intern musí do reportu napísať nejakých $b$ čísel. Ak intern klame, nemusí nutne zmeniť všetky svoje hodnoty, môže upraviť len ľubovoľnú ich podmnožinu.)
V prvom riadku vstupu sú čísla $a$, $b$ a $m$. V každom z nasledujúcich $a$ riadkov je $b$ čísel: merania spravené jedným z internov.
Všetky výsledky meraní aj číslo $m$ sú celé čísla z rozsahu od 0 po 99. (Keď intern klame, môže do reportu uviesť aj iné čísla, ak chce.)
Hodnoty $a$ a $b$ sú kladné celé čísla. V jednotlivých sadách platia nasledovné obmedzenia pre ich súčin:
| Sada | 1 | 2 | 3 | 4 |
|---|---|---|---|---|
| $\max a\times b$ | 7 | 99 | 999 | $99\,999$ |
Vypíšte jeden riadok a v ňom jedno číslo: minimálny počet internov, ktorí musia v reporte klamať, ak potrebujeme, aby medián všetkých $a\times b$ meraní vyšiel presne $m$.
Input:
5 5 8
1 2 3 4 5
10 9 8 7 6
25 24 23 22 21
18 16 17 19 20
11 13 12 14 15
Output:
1
Momentálne je medián všetkých meraní rovný 13. Na to, aby sa zmenšil na 8, napríklad stačí, ak štvrtý intern namiesto 18,16,17,19,20 dá do reportu 3,1,3,5,7.
Input:
5 5 8
1 2 25 24 23
3 4 22 21 20
5 6 19 18 17
7 16 15 14 13
8 12 11 10 9
Output:
2
Tu namerali interni tých istých 25 hodnôt, ale pri tom, ako ich majú teraz rozdelené, nestačí, aby klamal len jeden z nich.
Input:
1 5 30
30 50 10 20 40
Output:
0
Input:
1 5 27
30 50 10 20 40
Output:
1
Input:
3 1 20
10
10
10
Output:
2
Začneme tým, že si vyriešime jednoduchšiu úlohu: odignorujeme zatiaľ, že máme nejakých internov, a budeme sa zaujímať len o to, koľko najmenej čísel treba zmeniť, aby medián vyšiel presne $m$.
Predstavme si, že sme si všetky hodnoty usporiadali a pozreli sme sa do stredu poľa. Ak v strede poľa vidíme želanú hodnotu $m$, netreba meniť nič.
Ak vidíme hodnotu menšiu ako $m$, máme v poli priveľa malých čísel. Zistime si teda, pokiaľ v našom poli siahajú čísla menšie ako $m$. Nech sú primalé čísla nielen v strede poľa, ale aj na nasledujúcich $x-1$ políčkach. Čo to pre nás znamená? Aspoň $x$ spomedzi čísel v pôvodnom poli nutne musíme zväčšiť na aspoň $m$, inak budeme mať ešte stále priveľa malých čísel a v strede usporiadaného poľa bude naďalej primalá hodnota.
Na druhej strane však ľahko nahliadneme, že keď zmeníme ľubovoľných $x$ primalých hodnôt na hodnotu presne $m$, dostaneme platné riešenie. Totiž keď po tejto zmene preusporiadame prvky, prvky s novou hodnotou $m$ obsadia presne $x$ posledných políčok z úseku, v ktorom dovtedy boli primalé hodnoty – a teda aj v strede poľa už dostaneme hodnotu $m$.
Situácia, keď sme v strede poľa uvideli priveľkú hodnotu, sa rieši symetricky.
Bez ujmy na všeobecnosti predpokladajme, že súčasný medián je primalý, potrebujeme teda niektoré prvky zväčšiť. A vyššie popísaným spôsobom vieme nájsť $x$ také, že určite treba spraviť aspoň $x$ zmien.
Pre každého interna si teraz zistíme, koľko má medzi svojími meraniami čísel menších ako $m$. Nanajvýš toľko ich samozrejme tento konkrétny intern vie zväčšiť na $m$. My hľadáme takú sadu internov, aby ich bolo čo najmenej a aby dokopy vedeli zväčšiť aspoň tých potrebných $x$ hodnôt. Je zjavné, že toto vieme spraviť pažravo: usporiadame si internov podľa toho, koľko hodnôt vedia zväčšiť na $m$, a budeme ich postupne brať (začínajúc tým, ktorý vie zmien spraviť najviac) až kým nebudú dokopy vedieť spraviť dostatočný počet zmien.
Zjavne platí, že keď nami vybraná skupina internov spraví ľubovoľných $x$ zmien (hodnoty menšej ako $m$ na hodnotu $m$), dostaneme platné riešenie. A tiež platí, že žiadna menšia skupina internov takto veľký počet zmien nevie spraviť, nájdené riešenie je teda optimálne.
K implementácii už len podotknem, že usporadúvať samotné čísla vôbec netreba – totiž si stačí v lineárnom čase spočítať, koľko je primalých a koľko je priveľkých. Pri usporadúvaní internov podľa počtu dobrých zmien, ktoré vedia spraviť, som použil CountSort, celkovo má teda nižšie uvedená implementácia časovú zložitosť lineárnu od veľkosti vstupu: $O(ab)$.
A, B, M = [ int(_) for _ in input().split() ]
data = [ [ int(_) for _ in input().split() ] for a in range(A) ]
pocet_mensich = sum( x<M for row in data for x in row )
pocet_vacsich = sum( x>M for row in data for x in row )
max_moze = (A*B - 1) // 2
zmenit = 0
zmenitelny = lambda x: False
if pocet_mensich > max_moze:
zmenit = pocet_mensich - max_moze
zmenitelny = lambda x: x < M
if pocet_vacsich > max_moze:
zmenit = pocet_vacsich - max_moze
zmenitelny = lambda x: x > M
# pocet_internov[x] bude pocet internov, ktori vedia spravit presne x zmien
pocet_internov = [ 0 for _ in range(B+1) ]
for row in data:
pocet_internov[ sum( zmenitelny(x) for x in row ) ] += 1
vybrat = 0
for b in range(B,0,-1):
while zmenit > 0 and pocet_internov[b] > 0:
pocet_internov[b] -= 1
zmenit -= b
vybrat += 1
print(vybrat)
Korešpondenčný seminár z programovania zastrešuje občianske združenie Trojsten.
Trojsten, o.z.
FMFI UK, Mlynská dolina
842 48 Bratislava
Programátorská súťaž pre základoškolákov
Materiály a úlohy na výučbu programovania
Intenzívny programátorský zážitok v lete