Zoznam úloh

5. Ááále, to sa spraví...

Zadanie

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.

Úloha

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.)

Formát vstupu

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$

Formát výstupu

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$.

Príklady

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.

Späť k pôvodnej úlohe

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.

Implementácia

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)
Pre odovzdávanie sa musíš prihlásiť.
Trojsten

Korešpondenčný seminár z programovania zastrešuje občianske združenie Trojsten.

Kontakt
Ďalšie projekty