Informatyczny kącik olimpijski
Egzamin
Tym razem omówimy zadanie Egzamin, które pojawiło się w 2010 roku na Junior Balkan Olympiad in Informatics w Szumen (Bułgaria).
Zadanie. Egzamin: Dany jest ciąg złożony z
liczb naturalnych, oraz liczba
Ile jest podciągów ciągu
których suma elementów wynosi przynajmniej
Dla przykładu,
ma
podciągów, które mają sumę przynajmniej
Są to podciągi:
oraz
Rozwiązanie
Pomysł, który jako pierwszy nasuwa się na myśl, polega na obliczeniu sumy każdego podciągu, a następnie zliczeniu tych sum, których wartość jest nie mniejsza niż
Zastanówmy się teraz, jaka jest złożoność opisanego rozwiązania. Ciąg ma
podciągów długości
podciągów długości
wreszcie
podciągów długości
Zatem, suma długości wszystkich podciągów wynosi:
Powyższą sumę można zinterpretować nieco inaczej: każdy z
elementów ciągu
należy do
podciągów (dla ustalonego elementu
pozostałych elementów tworzy
podciągów). Zatem liczba składników we wszystkich sumach wynosi
co daje nam złożoność czasową
Rozwiązanie
Spróbujmy przyspieszyć powyższe rozwiązanie. Będziemy obliczali sumy podciągów w kolejności niemalejących długości (najpierw podciągi długości jeden, potem długości dwa, trzy, itd.). Załóżmy, że obliczamy sumę podciągu (podciąg ma długość
indeksy kolejnych elementów tworzą ciąg
). Suma elementów tego ciągu to suma podciągu
(którą obliczyliśmy wcześniej, ponieważ przeglądamy podciągi od najkrótszych do najdłuższych) powiększona o
W tym podejściu obliczenie sumy każdego z
podciągów odbywa się w czasie stałym, co daje nam złożoność czasową
Rozwiązanie
W tym rozwiązaniu skorzystamy z techniki Meet in the middle.
Podzielmy ciąg na dwa ciągi równej długości (jeśli długość ciągu jest nieparzysta, wtedy niech pierwszy ciąg zawiera o jeden element więcej): lewy
oraz prawy
Następnie, dla każdego z nich, obliczmy sumy podciągów. Możemy to zrobić w czasie
korzystając z algorytmu opisanego w poprzedniej sekcji. Niech
oznacza sumy podciągów
i niech
oznacza sumy podciągów
Zauważmy teraz, że dowolny podciąg ciągu
spełnia jeden z trzech poniższych warunków:
Warunek (I): wszystkie elementy należą do
Aby obliczyć liczbę podciągów o sumie przynajmniej których wszystkie elementy należą do
wystarczy zliczyć te elementy ciągu
które mają wartość przynajmniej
Formalnie jest to moc zbioru:
Sprawdzenie tego warunku odbywa się w czasie liniowym od liczby podciągów
czyli
Warunek (II): wszystkie elementy należą do
Analogicznie jak warunek (I).
Warunek (III): część elementów należy do
część należy do
W tym przypadku chcemy obliczyć liczbę takich par dla
oraz
że
Ten problem rozbijemy na
podproblemów. Dla każdego
obliczymy, ile jest takich
że
W tym celu posortujmy ciąg i otrzymany ciąg nazwijmy
Załóżmy, że obliczamy wynik dla ustalonego
Za pomocą wyszukiwania binarnego szukamy takiego najmniejszego
że
Jeśli takie
istnieje, wtedy dla każdego
zachodzi
ponieważ
jest niemalejący. Stąd,
należy do
par, które mają sumę przynajmniej
Jeśli zaś takie
nie istnieje, to
nie tworzy żadnej pary o sumie przynajmniej
Faza sortowania zajmuje czas Wyznaczenie liczby poprawnych par, dla ustalonej wartości, za pomocą wyszukiwania binarnego zajmuje czas
Wszystkich wartości do sprawdzenia jest
(
jest rzędu
), co daje całkowitą złożoność
Przykład. Prześledźmy opisany algorytm na przykładzie ciągu w którym szukamy liczby podciągów o sumie przynajmniej
Najpierw dzielimy ciąg
na dwa ciągi i dla każdego z nich obliczamy sumy wszystkich jego podciągów:

Z warunku (I) mamy podciąg, z warunku (II) również
Przechodzimy do warunku (III). Najpierw sortujemy
otrzymując
Teraz wyznaczamy wyniki dla kolejnych elementów
:
Ostatecznym wynikiem jest:
