4 - Carina
Vremensko ograničenje | Memorijsko ograničenje |
---|---|
500ms | 16MB |
Mali Perica, igrajući igru ”Flappy Bird”, je primetio da ptica uvek ujednačeno skakuće, bez obzira na to u kojoj je fazi padanja kao i da se nikad ne umara. Ovo je Perici bilo jako neprirodno, tako da je rešio da napravi novu verziju igrice, TheBird™. Međutim, komisija ga je odmah prijavila policiji za krađu autorskih prava, tako da su mu mogućnosti za distribuciju igrice u inostranstvo sada jako ograničene.
Perica je napravio određen broj kopija igrice, i namerava da ih prenese od firme (mesto A) do distributera za strano tržište (mesto B). Da bi to uradio, na raspolaganju mu je jedan šleper koji može da prenese ograničen broj igrica odjednom. Na putu od mesta A do mesta B nalazi se određen broj kontrolnih punktova carine: ukoliko Perica prevozi bar jednu kopiju igrice u momentu ulaska na punkt, mora pokloniti carinicima jednu kopiju kao mito. Na punktu se kopije mogu istovariti, pa ponovo pokupiti kasnije. Perica takođe ne želi da se vraća nazad u mesto A više od \(X\) puta (da ne bi ispao sumnjiv saobraćajcima).
Pericu interesuje koliki je najveći broj kopija igrice TheBird™ koji se mogu dopremiti do mesta B.
Ulaz
U prvom i jedinom redu standardnog ulaza nalaze se četiri cela broja, \(N\), \(C\), \(L\) i \(X\), koji predstavljaju broj kopija igrice, kapacitet šlepera, broj punktova i maksimalan broj vraćanja u mesto A, redom.
Izlaz
U prvom i jedinom redu standardnog izlaza ispisati najveći broj kopija igrice koje se mogu dopremiti.
Primer 1
Ulaz
Izlaz
Objašnjenje primera
Perica može najpre da napuni šleper sa \(1000\) igrica, da ga doveze do \(500\)-tog punkta, i da tu istovari \(500\) kopija koje su mu ostale u šleperu. Zatim se vraća u mesto A i na isti način dovozi još \(500\) kopija na \(500\)-ti punkt. Tada ponovo puni šleper sa prethodno ostavljenih \(500\) kopija, i tako dolazi do mesta B, sa \(500\) dopremljenih kopija. Nije moguće napraviti strategiju koja donosi više kopija do mesta B.
Ograničenja
- \(1 \leq N, C, L \leq 10^{18}\).
- \(0 \leq X \leq 10^6\).
Test primeri su podeljeni u dve disjunktne grupe:
- U test primerima vrednim \(40\) poena važi \(N, C, L \leq 10^6\).
- U test primerima vrednim 60 poena nema dodatnih ograničenja.
Autor | Tekst i test primeri | Analiza rеšenja | Testiranje |
---|---|---|---|
Petar Veličković | Petar Veličković | Petar Veličković | Dušan Zdravković |
Zadatak Carina spada u probleme srednje težine na drugim Kvalifikacijama, i odlikuje se izuzetno kratkim rešenjem; ideja je da rešavaoci mnogo više vremena potroše na smišljanje pravilnog rešenja nego na samu implementaciju.
Pre svega, primetimo da je jedini efekat broja \(X\) ograničavanje koliko igrica možemo izneti iz mesta A; ovo je ekvivalentno tome da je \(N=\min(N, C\cdot (X+1))\). Pošto je broj \(X\) ograničen sa \(10^6\), ovo samo po sebi treba da sugeriše da je traženi algoritam reda veličine \(O(X)\); međutim da bismo došli do ovog algoritma neophodno je najpre napraviti nekoliko zapažanja.
Najpre primetimo da je jedna od optimalnih strategija vrlo jednostavna: svaki put punimo šleper do vrha, i donosimo igrice na prvi sledeći punkt, gde gubimo jednu i istovaramo ostale; ovo ponavljamo dok ne prenesemo sve igrice na prvi punkt. Ovim smo izgubili \(\lceil \frac{N}{C}\rceil\) igrica, tj. najmanji ceo broj veći ili jednak \(\frac{N}{C}\). Ako ovako nastavimo, preneli smo maksimalan moguć broj igrica u mesto B; ovo možemo naivno predstaviti sledećim C++ kodom:
long long carina(long long n, long long c, long long l)
{
for (long long i=0;i<l;i++)
{
long long lost = n/c;
if (c * lost != n) lost++;
n -= lost;
}
return n;
}
Ovo rešenje je očigledno složenosti \(O(L)\), i donosi oko \(50\) bodova. Zapažanje koje nam pomaže da dođemo do bržeg rešenja je da primetimo da se više koraka mogu ”spakovati” u jedan, tj. često će postojati više od jednog koraka tokom ove strategije gde ćemo izgubiti isti broj igrica; ako efikasno odredimo broj koraka koji smemo napraviti tako da u svakom koraku gubimo isti broj igrica, onda možemo šleper odmah nositi do te pozicije; tj. ne moramo prelaziti jedan po jedan punkt.
Da bismo odredili ovu poziciju, potrebno je posmatrati ostatak pri deljenju \(N\) sa \(C\). Nazovimo ovaj ostatak \(R\). Neophodan broj povrataka na punkt sa kojeg smo krenuli trenutni korak se smanjuje za bar jedan kada se ovaj ostatak izgubi; kako u svakom jediničnom koraku gubimo \(\lceil \frac{N}{C}\rceil\) igrica, broj potrebnih koraka da se ovo desi je \(k = \lceil \frac{R}{\lceil \frac{N}{C} \rceil} \rceil\). Ukoliko je \(R=0\), onda možemo uzeti \(R=C\).
Nakon što odredimo broj potrebnih koraka, možemo odmah otići sa punkta \(x\) na punkt \(x+k\) i usput oduzeti \(k\cdot \lceil \frac{N}{C} \rceil\) od \(N\), naravno vodeći računa o tome da li smo prekoračili mesto B.
Primetimo da ovo rešenje u svakom koraku smanjuje broj ”povrataka” šlepera za bar jedan, dakle složenost ovog algoritma je \(O(\frac{N}{C})\), što smo na početku ograničili sa \(O(X)\). Ovaj algoritam donosi \(100\) bodova.
04_carina.cpp | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
|