Informatyczny kącik olimpijski
Trzej znajomi
W tym odcinku omówimy rozwiązanie zadania "Trzej znajomi", które pojawiło się na drugim etapie XIII Młodzieżowej Olimpiady Informatycznej.
Zadanie. Trzej znajomi: Adam, Błażej i Cezary postanowili napisać ciąg liczb naturalnych. Każdy z nich miał inny pomysł na ciąg. Adam chciał napisać ciąg
Błażej ciąg
zaś Cezary ciąg
Znajomi długo nie mogli dojść do porozumienia, dlatego postanowili zbudować nowy ciąg
Ustalili, że na każdej pozycji wybiorą którąś ze swoich opcji, czyli
Koledzy zgadzają się, że różnica pomiędzy największym a najmniejszym elementem ciągu
powinna być jak najmniejsza. Jaką najmniejszą różnicę może mieć ciąg
Rozwiązanie
Zacznijmy od rozwiązania, które generuje wszystkie możliwe ciągi Takich ciągów jest
(wartość każdego z
elementów można wybrać na
sposoby). Spośród wygenerowanych ciągów należy wybrać ten, który ma najmniejszą różnicę pomiędzy największym a najmniejszym elementem, oraz wypisać tę różnicę. Dla ustalonego ciągu
znalezienie najmniejszego i największego elementu można wykonać w czasie
(przeglądamy kolejne elementy, pamiętając najmniejszy oraz największy). Rozwiązanie działa w czasie
Obserwacja:
Zauważmy, że dla ustalonych całkowitych możemy w czasie
sprawdzić, czy istnieje ciąg
którego wartości elementów należą do przedziału
Warunkiem koniecznym i wystarczającym jest, aby dla każdego indeksu
przynajmniej jeden z trzech elementów
należał do
Rozwiązanie
Niech i
oznaczają odpowiednio wartość najmniejszego i największego elementu w ciągach
i
Korzystając z powyższej obserwacji, wystarczy dla wszystkich par liczb całkowitych
i
sprawdzić, czy istnieje ciąg
którego wartości należą do przedziału
Spośród poprawnych przedziałów należy wybrać ten o najmniejszej różnicy
Wszystkich przedziałów do sprawdzenia jest
Zatem rozwiązanie zajmuje czas
Rozwiązanie
Niech będzie zbiorem wartości, które występują przynajmniej raz w ciągu
lub
Zauważmy, że wystarczy rozważać tylko takie przedziały
dla których
oraz
Moc zbioru
jest rzędu
(co najwyżej
różnych wartości może pojawić się w
ponieważ tyle jest w sumie elementów). Stąd do sprawdzenia mamy
przedziałów, zatem całkowita złożoność czasowa wynosi
Rozwiązanie
Okazuje się, że nie musimy sprawdzać wszystkich wyżej wymienionych przedziałów. Wystarczy, że dla każdego wyznaczymy takie najmniejsze
że istnieje ciąg
którego wartości elementów należą do
Ustalmy
dla którego szukamy najmniejszego
Następnie wartość
wyszukajmy binarnie w przedziale
Rozwiązanie działa w czasie
Rozwiązanie
Podobnie jak wyżej, dla każdego wyznaczymy najmniejsze poprawne
W tym celu skonstruujemy ciąg
którego największy element będzie możliwie najmniejszy. Dla każdego
mamy trzech kandydatów
Spośród nich wybieramy najmniejszego, który jest większy lub równy
Jeśli taki element nie istnieje, to znaczy, że nie istnieje ciąg
z minimalnym elementem
W przeciwnym przypadku
Dla ustalonego
wyznaczenie minimalnego
odbywa się w czasie
zatem całe rozwiązanie działa w czasie
Rozwiązanie
Każdy z elementów ciągów i
opiszmy parą liczb: wartość i indeks. W ten sposób otrzymamy
par:
Następnie posortujmy te pary rosnąco względem pierwszej współrzędnej, aby otrzymać ciąg
Zauważmy, że z ciągu
(dla
) można wybrać
elementów, które utworzą ciąg
jeśli
Innymi słowy, dla każdej pozycji (od
do
) musimy ustalić przynajmniej jeden element. Zatem chcemy znaleźć takie indeksy
że z
można zbudować ciąg
oraz
jest minimalne. Wystarczy, że dla każdego
od
do
znajdziemy najmniejsze takie
że z elementów
można zbudować ciąg
Do rozwiązania tego problemu wykorzystamy metodę gąsienicy. Na początku
Dopóki fragment
nie pozwala stworzyć poprawnego ciągu, to zwiększamy
o jeden. W przeciwnym przypadku przechodzimy do kolejnego
W każdym kroku zliczamy liczbę wystąpień każdego indeksu na rozpatrywanym fragmencie oraz pamiętamy liczbę różnych indeksów, które występują przynajmniej raz. Jeśli ta wartość jest równa
to wtedy rozpatrywany fragment tworzy ciąg
Sortowanie działa w czasie zaś faza szukania najkrótszych fragmentów dla każdego początku zajmuje czas
Zatem całe rozwiązanie działa w czasie