Miestnosť T2, niekedy začiatkom novembra:
“Už ste to počuli? Zdraželi pizzu v matickej jedálni! Čo budeme teraz robiť? Sme chodobní študenti, toľko si nemôžeme dovoliť zaplatiť za pizzu.”, rozliehalo sa v T2.
“Nebojte, mám plán”, povedal Krtko, “Aďo doniesie tú pizza piecku čo sľúbil, a budeme si piecť pizzu tu.”
“To by som nerobil, viete ako veľmi zdraželo droždie?”, ozval sa Kubo, ktorý sa z ničoho nič objavil v T2 tiež.
“Tak budeme robiť kváskové cesto. To len zoženieme zopár kváskov, a oni potom budú rásť samé…”
…
Tak sa aj stalo. Nakúpili sa kvásky do T2, s tým, že sa z nich bude piecť pizza. Bohužiaľ, prišiel lockdown, a vedúci prestali chodiť do T2. A tak tam kvásky len tak ležali, nikto z nich nebral, a nepozorovane sa delili na viac a viac kváskov.
Vedeli by ste vypočítať, koľko kváskov bude v T2, keď sa vrátime do školy?
Do T2 sa nakúpilo presne $n$ kváskov.
Rast kváskov funguje nasledovne: Každý kvások má svoj čas – počet dní do rozdelenia kvásku na viac kváskov. Tento čas je číslo od $0$ po $8$ (vrátane). Kvások sa rozdelí vtedy, keď je jeho čas rovný $0$. Z každého kvásku vznikne presne $k$ ďalších kváskov s časom $8$. Čas pôvodného kvásku sa nastaví späť na $6$.
Vašou úlohou je povedať, koľko kváskov bude v T2 po $t$ dňoch.
Na prvom riadku sa nachádzajú $3$ medzerou oddelené čísla $n$ – počet kváskov v T2, $k$ – počet kváskov na ktoré sa každý kvások rozdelí keď dosiahne čas 0 a $t$ – deň, v ktorý nás zaujíma počet kváskov.
Na druhom riadku sa nachádza $n$ medzerou oddelených čísel $c_i$ – časy jednotlivých kváskov v deň $0$.
Na výstup vypíšte jedno číslo, počet kváskov po $t$ dňoch. Dajte si pozor, že toto číslo môže byť veľké. Odporúčame použiť $64$ bitovú premennú (long long v C/C++).
Nezabudnite za číslom vypísať znak konca riadku.
Sú 4 sady vstupov. Platia v nich nasledovné obmedzenia:
| Sada | 1 | 2 | 3 | 4 |
|---|---|---|---|---|
| $1 \leq n \leq$ | $20$ | $40$ | $50$ | $60$ |
| $0 \leq k \leq$ | $1$ | $5$ | $50$ | $150$ |
| $1 \leq t \leq$ | $20$ | $40$ | $150$ | $180$ |
V druhej sade navyše platí, že všetky časy kváskov sa rovnajú.
Input:
3 2 3
2 0 6
Output:
7
Kvásky budú vyzerať nasledovne. Po prvom dni vzniknú z druhého kvásky $2$ ďalšie, a teda (ak nové kvásky pridávame na koniec) kvásky budú mať časy 1 6 5 8 8. Po druhom dni budú mať kvásky časy 0 5 4 7 7. Po treťom vzniknú ďalšie dva kvásky (tie opäť pridávame na koniec), a teda budú mať časy: 6 4 3 6 6 8 8. Kváskov po $3$ dňoch bude 7.
Input:
3 0 2
1 2 3
Output:
3
V tomto prípade z každého kvásku vznikne $0$ ďalších, a teda sa počet kváskov vôbec nemení.
Input:
1 1 11
1
Output:
4
V tomto prípade v čase 10 budú časy kváskov 4 6 6 8
Najjednoduchšie riešenie je krok po kroku odsimulovať, ako sa mení počet kváskov. Vieme to urobiť tak, že budeme mať pole, kde na indexe $i$ budeme mať čas kvásku $i$. Potom stačí $t$ krát prejsť celé pole, a každému kvásku znížiť čas o $1$. Ak je nový čas kvásku rovný $0$, tak na koniec poľa pridáme $k$ nových kváskov s časom $8$, a tomuto kvásku nastavíme čas opäť na $6$. Je treba si dať pozor, aby sme v tomto prechode poľom časy novopridaných kváskov už nezmenšovali, alebo aby sme pridávali nové kvásky s vekom $9$ a teda po prejdení celého poľa mali tieto kvásky správny čas.
Výsledok, počet kváskov po $t$ dňoch je rovný dĺžke poľa.
Čo sa týka časovej zložitosti, tak náš program $t$ krát prejde celé pole. Pole bude mať na konci dĺžku najviac $nk^{t/6}$. Prečo? Ak si predstavíme, že by mali všetky kvásky rovnaký čas, a nové kvásky by vznikali s časom $6$, tak každých $6$ dní by z sa počet kváskov zväčšil $k$ krát. To znamená, že po $6$ dňoch by sa počet kváskov zväčšil na $k$ násobok, po $12$ dňoch na $k \cdot k = k^2$ násobok, a po $t$ dňoch na $k^{t/6}$ násobok. (Všimnite si, že sme urobili horný odhad, keďže sme predpokladali, že nové kvásky vznikajú s menším časom, a teda v skutočnosti z nich nové kvásky vzniknú skôr.) Pole teda prejdeme $t$ krát, a vždy bude mať dĺžku najviac $nk^{t/6}$.
Časová zložitosť je teda rovná tomu, že $t$ krát prejdeme pole s maximálnou dĺžkou $nk^{t/6}$, takže $O(t \cdot nk^{t/6})$. Pamäťová zložitosť je rovná výslednej dĺžke poľa, teda $O(nk^{t/6})$.
Takéto riešenie stačí na prvé $2$ sady.
#include<iostream>
#include<vector>
using namespace std;
int main(){
long long n,k,t;
int max_cas_kvasku = 7;
int cas_noveho_kvasku = 8;
cin>>n>>k>>t;
vector<long long> kvasky;
for(int i=0;i<n;i++){
int tmp;
cin>>tmp;
kvasky.push_back(tmp);
}
for(int c=0;c<t;c++){
for(int i=kvasky.size()-1;i>=0;i--){
if(kvasky[i]==0){
for(int j=0;j<k;j++)
kvasky.push_back(cas_noveho_kvasku);
kvasky[i]=max_cas_kvasku;
}
kvasky[i]--;
}
}
cout<<kvasky.size()<<endl;
return 0;
}
#!/usr/bin/env python3
max_cas_kvasku = 7
cas_noveho_kvasku = 8
n, k, t = map(int, input().split())
kvasky = list(map(int, input().split()))
for i in range(t):
pocet_novych_kvaskov = 0
for j in range(len(kvasky)):
if kvasky[j] == 0:
kvasky[j] = max_cas_kvasku - 1
pocet_novych_kvaskov += 1
else:
kvasky[j] -= 1
kvasky += [cas_noveho_kvasku for i in range(pocet_novych_kvaskov*k)]
print(len(kvasky))
Môžeme si uvedomiť, že v predchádzajúcom riešení robíme pre všetky kvásky v zásade tú istú vec: zmenšíme ich čas, a poprípade pridáme nejaké nové. Takéto niečo ale nemusíme robiť pre každý kvások zvlášť, môžeme to robiť pre všetky kvásky s rovnakým časom spolu. Ak máme napríklad tri kvásky, a z každého z nich ide akurát vzniknúť $6$ nových, tak dokopy vieme povedať, že z nich vznikne $18$ nových kváskov s vekom $8$.
Skúsme si teda namiesto poľa, v ktorom na indexe $i$ máme čas kvásku $i$ pamätať kvásky inak. Pamätajme si ich tak, že v poli na indexe $i$ budeme mať počet kváskov s časom $i$. Takto dosiahneme, že dĺžka poľa sa nebude zväčšovať, ale bude mať vždy dĺžku $9$ (keďže najväčší možný čas kvásku je $8$).
Ako teda presne budeme simulovať rast kváskov?
Opäť $t$ krát prejdeme celé pole, a kvásky na indexoch $1$ až $8$ posunieme na o $1$ menší index (zmenšíme im čas o $1$), kvásky na indexe $0$ pripočítame ku kváskom na indexe $6$ a vytvoríme príslušný počet nových kváskov s časom $8$. Treba si dať pozor na to v akom poradí to robíme, aby sme kvásky z indexu $0$, ktoré presunieme na index $6$ už viac neposúvali.
Výsledok, teda počet kváskov zistíme tak, že spočítame počty kváskov s jednotlivými časmi.
Náš program $t$ krát prejde celé pole, a každý raz urobí niekoľko málo operácií (pripočítanie a vynásobenie zopár čísel). Pole má celý čas dĺžku $9$, a prejdeme ho $t$ krát, takže časová zložitosť je $O(9t) = O(t)$.
Čo sa týka pamäťovej zložitosti, tak náš program si okrem niekoľko málo premenných pamätá len pole dĺžky $9$, takže pamäťová zložitosť je $O(9) = O(1)$.
#include<iostream>
#include<vector>
using namespace std;
int main(){
long long n,k,t;
int max_cas_kvasku = 7;
int cas_noveho_kvasku = 8;
cin>>n>>k>>t;
vector<long long> pocty_kvaskov(cas_noveho_kvasku+1, 0);
for(int i=0;i<n;i++){
int tmp;
cin>>tmp;
pocty_kvaskov[tmp]++;
}
for(int i=0;i<t;i++){
long long nove_kvasky = pocty_kvaskov[0];
for(int j=0;j<cas_noveho_kvasku;j++){
pocty_kvaskov[j] = pocty_kvaskov[j+1];
}
pocty_kvaskov[cas_noveho_kvasku] = nove_kvasky*k;
pocty_kvaskov[max_cas_kvasku-1] += nove_kvasky;
}
long long pocet_kvaskov = 0;
for(int i=0;i<=cas_noveho_kvasku;i++)
pocet_kvaskov += pocty_kvaskov[i];
cout<<pocet_kvaskov<<endl;
return 0;
}
#!/usr/bin/env python3
max_cas_kvasku = 7
cas_noveho_kvasku = 8
n, k, t = map(int, input().split())
kvasky = list(map(int, input().split()))
pocty_kvaskov = {i:0 for i in range(0, cas_noveho_kvasku+1)}
for i in kvasky:
pocty_kvaskov[i] += 1
for i in range(t):
nove_kvasky = pocty_kvaskov[0]
for j in range(1, max_cas_kvasku):
pocty_kvaskov[j-1] = pocty_kvaskov[j]
pocty_kvaskov[max_cas_kvasku-1] = nove_kvasky
pocty_kvaskov[max_cas_kvasku-1] += pocty_kvaskov[max_cas_kvasku]
pocty_kvaskov[max_cas_kvasku] = pocty_kvaskov[cas_noveho_kvasku]
pocty_kvaskov[cas_noveho_kvasku] = nove_kvasky * k
print(sum(pocty_kvaskov.values()))
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