Editorial for Filozof
Submitting an official solution before solving the problem yourself is a bannable offence.
Author:
Analiza problema
Ako sa označimo koordinate donjeg levog temena pravougaonika sa rednim brojem , a sa i koordinate gornjeg desnog temena pravougaonika sa rednim brojem , onda će kordinate donjg levog temena obuhvatajućeg pravougaonika nakon dodavanja pravougaonika broj biti xo_j=\min{x_{j-k+1}, x_{j-k+2},...x_j}, \quad yo_j=\min{y_{j-k+1}, y_{j-k+2},...y_j}. Jasno, koordinate gornjeg desnog temena će biti:
xxo_j=\max{xx_{j-k+1}, xx_{j-k+2},...xx_j}, \quad yyo_j=\max{yy_{j-k+1}, yy_{j-k+2},...yy_j}.
Ako je , onda se formule neznatno menjaju te će koordinate donjeg levog temena biti
xo_j=\min{x_{1}, x_{2},...x_j}, \quad yo_j=\min{y_{1}, y_{2},...y_j}.
Analogno bi se određivale koordinate gornjeg desnog temena obuhvatajućeg pravougaonika.
Jasno, stranice minimalnog obuhvatajućeg pravougaonika, nakon -tog dana imaju dužine
\(None\)dx_j = xxo_j - xo_j,\quad dy_j=yyo_j-yo_j,
\(None\)
a dužine stranica minimalnog obuhvatajućeg pravougaonika za kompletan period od dana će biti jednake maksimumima odgovarajućih nizova sa dužinama.
Prema tome, potrebno je samo određivati minimume (ili maksimume) za svakih uzastopnih elemenata nekog niza (niza sastavljenog od ili koordinata temena pravougaonika). Opisaćemo kako određujemo minimume od svakih uzastopnih elemenata, a slično se odre]uju maskimumi.
Svakako se na prvi pogled nameće pravolinijsko rešenje u kome se za svaki podniz od uzastopnih ponovo izračunava minimum i to rešenje ima složenost .
Malo profinjenje ovog pravolinijskog rešenja dobijamo tako što pokušamo da iskoristimo prethodno izračunati minimum. Naime, pretpostavimo da smo završili obradu elementa i već izračunali minimum podniza od uzastopnih kome je poslednji element . Kada se pomerimo na sledeći element, treba da izračunamo . Ako je , onda će biti jednako baš (). Ako je pak , onda ne mora biti minimum od poslednjih uzastopnih. Međutim, ako je , onda je prethodni minimum bio baš jednak elementu koji "ispada" ia bloka uzastopnih i zbog toga treba ponovo izračunati minimum poslednjih . Složenost ovakvog rešenja zavisi od izgleda ulaznih podataka (tj. od toga koliko često se dešava drugi slučaj), a u najnepovoljnijem slučaju može biti .
Sledeća varijanta rešenja se dobija tako što se "aktuelni elementi" (tj. poslednjih obrađenih) čuvaju u min-hip-u. To obezbeđuje da u konstantnom vremenu određujemo minimum od uzastopnih. Međutim, treba imati u vidu da pri obradi narednog elementa niza, taj element treba dodati u hip i istovremeno element koji ispada iz bloka aktuelnih izbaciti iz hip-a. Složenost ovih operacija je (pošto se u hipu nalazi elemenata) pa je tako složenost kompletnog rešenja .
Za najefkasnije rešenje zamislimo da smo ceo niz podelili na disjunktne blokove sastavljene od po uzastopnih: prvi blok čine elementi od prvog do -og, drugi od -og do -og, treći od -og do -og, itd. Tada će svaki blok od tačno uѕastopnih biti sastavljen od delova iz ne više od dva uzastopna bloka: desni kraj jednog bloka (neka je to blok ) i levi kraj narednog bloka (neka je to blok ). Minimum tog bloka se može lako izračunati ako su prethodno izračunati minimumi za odgovarajuće delove iz blokova i (kao manji od ta dva minimuma). Minimumi svih ovih delova se mogu jednostavno izračunati sa dva prolaza kroz niz: jedan prolaz za računanje minimuma levih krajeva i jedan prolaz za računanje minimuma desnih krajeva.
Prikažimo još jedan postupak za određivanje minimuma za svakih uzastopnih. Element je kandidat za najmanji element podnizova (od uzastopnih) koji se završavaju na pozicijama . Međutim, ako za () važi da je , onda prestaje biti kandidat za minimum podnizova koji se završavaju na pozicijama (znači može se eliminisati iz razmatranja). Možemo posmatrati i obratno: nakon uključivanja elementa , svi elementi ubačeni pre koji imaju osobinu da su veći (ili jednaki) od ne mogu biti više kandidati za minimum od uzastopnih (bez obzira što se nalaze u bloku od poslednjih uzastopnih). Zbog toga se mogu izbaciti iz razmatranja svi elemente niza koji imaju osobinu da su veći (ili jednaki) od . Primetimo da se taj element () dodaje na kraj liste kandidata (kao poslednji kandidat), zato što je on poslednji dodati i u jednom trenutku svi pre njega dodati će biti izbačeni te on ima šanse da bude najmanji u podnizu od poslednjih nakon izbacivanja tih prethodnih. Element koji se nalazi na početku liste kandidata jeste baš najmanji za naredni blok uzastopnih. Ali kada u jednom trenutku on bude na rastojanju bar od elementa koji se trenutno obrađuje, on prestaje da bude kandidat i zato se briše iz te liste kandidata. Prema tome, lista kandidata ima osobinu da se sa jedne strane (početka) elementi izbacuju kada prestanu da budu aktuelni, dok se sa druge strane i dodaju, ali isto tako i izbacuju kada se pojavi neki manji.
Algoritamske smernice
Radi ilustracije moguće implementacije, prilažemo telo funkcije koja kao argumente dobija: dužinu nizova koji sadrže koordinate levih krajeva pravougaonika i koordinate desnih krajeva tih pravougaonika (broj ), broj , kao i nizove sa koordinatama levih krajeva i koordinatama desnih krajeva, a koja vraća širinu minimalnog obuhvatajićeg pravougaonika. Indeksiranje elemenata nizova kreće od nula (0).
Jedna moguća implementacija ѕasnovana na podeli niza uz blokove dužine može imati sledeći izgled:
int solve(int n, int k, int left[], int right[])
{
int pref_min[MAXN], pref_max[MAXN];
int suff_min[MAXN], suff_max[MAXN];
for(int i = 0; i < n; i++)
pref_min[i] = (i % k == 0) ? left[i] : min(pref_min[i - 1], left[i]);
for(int i = n - 1; i >= 0; i--)
suff_min[i] = (i % k == k - 1) ? left[i] : min(suff_min[i + 1], left[i]);
for(int i = 0; i < n; i++)
pref_max[i] = (i % k == 0) ? right[i] : max(pref_max[i - 1], right[i]);
for(int i = n - 1; i >= 0; i--)
suff_max[i] = (i % k == k - 1) ? right[i] : max(suff_max[i + 1], right[i]);
int res = 0;
for(int i = 0; i < n; i++)
{
int low = min(pref_min[i], suff_min[max(i - k + 1, 0)]);
int high = max(pref_max[i], suff_max[max(i - k + 1, 0)]);
res = max(res, high - low);
}
return res;
}
Implementacija zasnovana na formiranju liste (reda) kandidata za minimum (maksimum) od svakih uzastopnih može imati sledeći izgled:
int solve(int n, int k, int x1[], int x2[]) {
int dxm, dxt;
int qx1[MAXN], qx2[MAXN];
int qx1s, qx1e, qx2s, qx2e;
qx1s = qx2s = 0;
qx1e = qx2e = 1;
qx1[0] = qx2[0] = 0;
dxm = x2[0] - x1[0];
for (int i = 1; i < n; i++) {
if (i - qx1[qx1s] >= k) qx1s++;
if (i - qx2[qx2s] >= k) qx2s++;
while ((qx1e > qx1s) && (x1[qx1[qx1e-1]] >= x1[i])) qx1e--;
qx1[qx1e++] = i;
while ((qx2e > qx2s) && (x2[qx2[qx2e-1]] <= x2[i])) qx2e--;
qx2[qx2e++] = i;
dxt = x2[qx2[qx2s]]-x1[qx1[qx1s]];
if (dxt > dxm) dxm = dxt;
}
return dxm;
}
Written with StackEdit.
Comments