Članovi komisije su odlučili da takmičarima olakšaju čitanje tekstova, te je tekst ovog zadatka napisan formalno:
Dat je niz sa elemenata i broj . Na nizu se primenjuju operacije sledećeg tipa, sve dok je to moguće:
Izabere se podniz uzastopnih elemenata između pozicija i (uključujući i te dve pozicije), dužine tačno (dakle ) i ceo podniz se zameni jednim elementom, koji ima vrednost . Operacija označava operaciju bitovske disjunkcije. Detaljnije informacije možete pročitati u napomeni.
Formalno, označimo sa niz dobijen posle primene jedne operacije na nizu sa elemenata. Niz ima elemenata i to sa sledećim vrednostima:
za .
.
za .
Nakon što u nizu ostane manje od elemenata, posmatramo sumu elemenata koji su preostali. Cilj je da minimizujete sumu elemenata koji preostanu na kraju.
Opisi funkcija
Potrebno je da implementirate funkciju
Funkcija se poziva samo jednom na početku ivršavanja programa, a njeni parametri su , i . Povratna vrednost funkcije reši je minimalna suma elemenata, nakon primene najvećeg mogućeg broja operacija. Niz A je indeksiran od 1.
Primer
Neka je , , . Nakon primene operacije na poslednja tri elementa originalnog niza , dobija se niz sa sumom . Lako se utvrđuje da je ovo najmanja moguća suma, te je potrebno vratiti vrednost .
Ograničenja
.
.
Podzadaci
Test primeri su podeljeni u podzadatka:
[7 poena]:.
[9 poena]: i .
[15 poena]: Sve vrednosti u nizu su ili i .
[22 poena]:.
[29 poena]:.
[18 poena]: Nema dodatnih ograničenja
Detalji implementacije
Potrebno je da pošaljete tačno jedan fajl kompresovani_niz.cpp koji implementira pomenute funkcije. Osim traženih funkcija, vaš fajl može sadržati i dodatne globalne promenljive, pomoćne funkcije i dodatne biblioteke.
Vaša funkcija moraju biti sledećeg oblika:
long long Resi(int N, int* A, int K);
Vašim programima je dozvoljeno da menjaju sadržaj nizova ali ne smeju da pristupaju van granica datih nizova.
Uz zadatak, obezbeđen vam je "template" fajl code.cpp koje možete koristiti i menjati po potrebi. Takođe vam je obezbeđen program grader.cpp koji služi da lakše testirate kodove. Ovaj program učitava sa standardnog ulaza sledeće podatke:
U prvom redu brojevi i .
U narednom redu brojeva: .
Zatim ovaj program zove vašu funkciju i ispisuje rezultate koje ona vrati.
Napomena
Operator disjunkcije je u C++ zapisan pomoću simbola |. Ova operacija se za nenegativne cele brojeve definiše na sledeći način. Prvo se brojevi zapišu u binarnom zapisu. Ukoliko jedan broj ima manje cifara od drugog, dopisuju mu se vodeće nule sve dok ne budu imali isti broj binarnih cifara. Tako se dobijaju dva niza binarnih cifara, označimo ih sa i . Zatim se za svaku poziciju računa pomoću sledećih pravila:
Za važi
Za važi
Za važi
Za važi
Niz binarnih cifara (koji možda ima vodeće nule) je binarni zapis rezultata, odnosno broja .
Bitovska disjunkcija između elemenata definiše se kao .
Autor
Tekst i test primeri
Analiza rеšenja
Testiranje
Aleksa Milisavljević
Aleksa Milisavljević
Aleksa Milisavljević
Vladimir Milenković
Rešenje kada
U ovom podzadatku možemo testirati svaki mogući niz primene operacija. Za dato imamo opcija za primenu prve operacije. Posle prvog koraka, broj elemenata se smanji za , pa u drugom koraku imamo opcija. Ukupno, postoji različitih sekvenci operacija koje rezultuju nizom dužine manje od . Prethodni proizvod je ograničen sa , pa je složenost ovog rešenja .
Rešenje kada i
Za naredne podzadatke moramo malo detaljnije analizirati kako primene operacija utiču na niz. Za ovaj podzadatak, dovoljno je primetiti da su elementi krajnjeg niza zapravo kompresovani blokovi uzastopnih elemenata u početnom nizu. Ti blokovi uzastopnih elemenata imaju dužinu , što je lako pokazati. Naime, u početnom nizu blokovi imaju dužinu . Svakom daljom kompresijom se takvih blokova spaja u jedan blok, koji po modulu ima dužinu . Konačno, za ovaj podzadatak možemo da analiziramo dva slučaja:
- tada krajnji niz ima dužinu , a vrednost tog elementa je vrednosti svih elemenata u početnom nizu
- tada krajnji niz ima dužinu ukoliko je neparno i , ukoliko je parno. Ukoliko je neparno, tada je vrednost jedinog elementa vrednosti svih elemenata u početnom nizu. Konačno, ukoliko je parno, možemo da iteriramo po završetku prvog bloka, koji se završava na nekom neparnom indeksu u početnom nizu i da posmatramo prefiksni i sufiksni elemenata početnog niza. Rešenje zadatka je minimum njihove sume.
Rešenje kada
Ovaj i naredne podzadatke rešavamo dinamičkim programiranjem. Vrednost će predstavljati minimalnu vrednost sume ukoliko se ograničimo isključivo na prvih elemenata niza. Prvo moramo primetiti da je uslov da se operacije primenjuju sve dok niz ima dovoljno elemenata suštinski nevažan. Naime, primenom operacije se suma elemenata niza ne može povećati, te je svakako uvek bolje primeniti što više operacija. Za svaku poziciju , iteriramo po završnoj poziciji prethodnog bloka. Rekurentna formula za naše dinamičko programiranje je , gde je (jer prema opservaciji iz prethodnog podzadatak važi da je dužina svakog bloka ). Ukoliko održavamo vrednost , dok iteriramo po , dobijamo rešenje složenosti .
Rešenje kada su sve vrednosti u nizu su ili i
I u ovom podzadatku ponovo posmatramo blokove. Svaki blok ima vrednost , ili . Međutim, blok koji se završava na nekoj poziciji može da ima samo dve vrednosti, a to su i (npr. ukoliko -ti element ima vrednost , blok koji se završava na poziciji nikako ne može da ima vrednost i obrnuto). Za svaku krajnju poziciju, fiksiramo jednu od te dve moguće vrednosti poslednjeg bloka i posmatramo sve moguće startne pozicije trenutnog bloka. Za njih možemo da održavamo minimum koristeći neku strukturu podataka, na primer set.
Rešenje kada
Rešenje ovog podzadatka predstavlja nadogradnju na rešenje podzadatka u kojem su sve vrednosti u nizu jednake ili . Možemo da primetimo da postoji najviše mogućih različitih vrednosti bloka koji se završava na poziciji za svako . Sada možemo da fiksiramo jednu od tih vrednosti i pronađemo najraniju poziciju (označimo tu poziciju sa ) na kojoj je trenutni blok mogao da počne da bi imao tu vrednost. Zatim, koristeći neku strukturu, npr. set pronađemo minimum vrednosti -ova prethodnog bloka od pozicije pa do . Ovo možemo da realizujemo koristeći set na sledeći način. Možemo da čuvamo set-ova, jedan za svaku krajnju pozicija moduo . U svakom od njih možemo da čuvamo vrednosti -ova sortirano po indeksu. Konačno kada ubacujemo u set koji odgovara modulu , treba da izbacimo sve one koje koji se pojavljuju pre njega, a imaju veću vrednost od . Kada tražimo minimum od pozicije do pozicije , možemo da pozovemo ugrađenu funkciju lower_bound, da bi pronašli prvi indeks veći od koji postoji u odgovarajućem set-u. Složenost ovog rešenja je .
Glavno rešenje
Za glavno rešenje i poslednji podzadatak, dovoljno je optimizovati složenost na . Ovo se može postići na primer tako što zamenimo set sa spars tabelom.