Informatyczny kącik olimpijski
Ciąg arytmetyczny i Kamyczki
Tym razem omówimy dwa zadania z jubileuszowej X Olimpiady Informatycznej Gimnazjalistów w roku szkolnym 2015/2016.
Zadanie (Ciąg arytmetyczny). Dany jest ciąg liczb naturalnych Naszym zadaniem jest odpowiedzieć na zapytań postaci: czy podsłowo jest ciągiem arytmetycznym?
Zacznijmy od przypomnienia definicji ciągu arytmetycznego. Otóż, jest ciągiem arytmetycznym, jeśli różnice między kolejnymi parami wyrazów są równe, czyli:
Rozwiązanie ( ). Najprostsze rozwiązanie polega na sprawdzeniu dla każdego zapytania, wprost z definicji, czy dany ciąg jest arytmetyczny. W tym celu wyznaczamy różnicę ciągu jako Następnie sprawdzamy, czy różnica między każdymi dwoma sąsiednimi wyrazami jest równa Powyższe rozwiązanie działa w czasie
Rozwiązanie ( ). Niech będzie ciągiem różnic między kolejnymi wyrazami:
Ciąg jest arytmetyczny, jeśli odpowiadający mu ciąg różnic jest stały (wszystkie wyrazy są równe). Niech zatem będzie najmniejszą liczbą w ciągu, zaś największą. Wówczas wszystkie różnice znajdują się w przedziale Stąd, jeśli to ciąg różnic jest stały, czyli pierwotny ciąg jest arytmetyczny. Do wyznaczenia najmniejszego i największego elementu w przedziale można wykorzystać drzewo przedziałowe, które pozwala zrealizować tę operację w czasie Całe rozwiązanie działa w czasie
Rozwiązanie ( ). Okazuje się, że istnieje jeszcze szybsze rozwiązanie. Zauważmy, że ciąg różnic możemy podzielić na fragmenty o tych samych wartościach:
Wówczas fragment jest stały, jeśli wszystkie jego wyrazy należą do jednej grupy. Przejdźmy teraz do opisu generowania grup. Ustalmy, że pierwsza różnica tworzy pierwszą grupę. Pozostałe różnice będziemy przeglądali od lewej do prawej. Jeśli rozpatrywana różnica jest równa poprzedniej, to rozszerzamy poprzednią grupę, w przeciwnym przypadku tworzymy nową grupę. Rozwiązanie działa w czasie
Zadanie (Kamyczki). Danych jest stosów kamyczków. Wysokości kolejnych stosów to Celem Małgosi, bohaterki zadania, jest opróżnienie wszystkich stosów. Dziewczyna w jednym ruchu może opróżnić jeden dowolnie wybrany stos (nazwijmy ten ruch A) lub zabrać po jednym kamieniu z wszystkich niepustych stosów (nazwijmy ten ruch B). Ile minimalnie ruchów musi wykonać dziewczynka, aby opróżnić wszystkie stosy?
Obserwacja. Istnieje optymalne rozwiązanie, w którym najpierw wykonujemy ruchy typu A, a następnie ruchy typu B.
Dowód. Weźmy dowolne optymalne rozwiązanie. Jeśli w tym rozwiązaniu istnieje taki ruch typu A, który występuje po jakimś ruchu typu B, to ruch nie ma wpływu na pozostałe stosy oraz wcześniejsze ruchy typu B nie są konieczne do wykonania ruchu Stąd ruch może zostać wykonany przed wszystkimi ruchami typu B.
Na mocy powyższej obserwacji w optymalnym rozwiązaniu najpierw wykonujemy ruchy typu A, a następnie ruchy typu B. Zauważmy, że maksymalna liczba ruchów typu A to (jest co najwyżej stosów do opróżnienia). Dla każdej możliwej liczby ruchów A (od 0 do ) obliczmy minimalną liczbę ruchów B, która pozwoli opróżnić wszystkie stosy.
Zastanówmy się teraz, jak dla ustalonej liczby oznaczającej liczbę ruchów A, wybrać stosów do usunięcia tak, aby zminimalizować liczbę ruchów B. Zauważmy wcześniej, że po wykonaniu ruchów typu A należy wykonać tyle ruchów B, ile wynosi wysokość najwyższego z pozostałych stosów. Stąd, aby zminimalizować liczbę ruchów typu B, należy wybrać najwyższych stosów, co minimalizuje wysokość najwyższego z pozostałych stosów.
Przejdźmy teraz do opisu sposobu znajdowania najwyższych stosów. Kolejność stosów nie ma znaczenia, dlatego zacznijmy od posortowania ciągu rosnąco oraz ustalenia, że Wówczas najwyższych stosów to: Zatem wynik dla ustalonego to (wykonujemy ruchów typu A, usuwając najwyższych stosów, oraz ruchów typu B, opróżniając wszystkie pozostałe stosy, z których najwyższy ma wysokość ).
Najmniejszą liczbą ruchów, potrzebną do opróżnienia wszystkich stosów, jest minimum z wyników dla każdego od 0 do Rozwiązanie działa w czasie