BOI 2016
CEOI 2017
BOI 2018
BOI 2019
BOI 2020
CEOI 2020
Szachowa gorączka
Mamy daną szachownicę o wierszach oraz kolumnach ().
Jest niezależnych zapytań,
każdy składający się z typu piona
(pionek, wieża, goniec, hetman lub król)
i dwóch liczb .
Należy wypisać minimalną liczbę ruchów, które pion musi wykonać,
aby z pozycji dotarł na pozycję ,
oraz na ile różnych sposobów może dotrzeć na tę pozycję
korzystając tylko z minimalnej możliwej ilości ruchów,
modulo .
Pionek
Jeżeli , to pionek może dostać się na żądane pole na dokładnie jeden sposób
w ruchach. W przeciwnym przypadku, pionek nie może się dostać na żądane pole.
Wieża
Jeżeli , to wieża może dostać się na żądane pole w jednym ruchu na dokładnie jeden sposób.
W przeciwnym przypadku, może dostać się w dwóch ruchach na dwa sposoby.
Hetman
Hetman potrafi się dostać w takiej samej liczbie ruchów, co wieża,
ale gdy wymaga dwóch ruchów, to czasem liczba sposobów jest większa, niż u wieży.
Dla każdej kombinacji par ruchów (do góry, w lewo, w prawo, po przekątnej w lewo do góry, w prawo do góry)
należy sprawdzić, czy hetman może się dostać na żądane pole korzystając z takich ruchów w takiej kolejności
nie wychodząc poza planszę (przy czym jeżeli korzysta z dwóch ruchów po przekątnej,
to trzeba jeszcze porównać parzystość liczb oraz ).
Goniec
Goniec może się dostać na żądane pole wtedy i tylko wtedy,
gdy liczby oraz mają taką samą parzystość.
Bez straty ogólności załóżmy jaki jest pierwszy ruch gońca
(po przekątnej w lewo, czy w prawo).
Żeby obliczyć minimalną liczbę ruchów,
można rozważyć zachłanne zmienianie kierunku ruchu
dopiero wtedy, gdy goniec uderzy w brzeg planszy.
Niech będzie polem w wierszu , w którym goniec skończy taki proces.
Jeżeli , to jest to najkrótsza i jedyna taka ścieżka.
W przeciwnym przypadku, trzeba rozważyć dwa przypadki,
zależnie od sposobu dotarcia do ostatniego wiersza.
Jeżeli na przykład goniec dotarł do ostatniego wiersza poruszając się w prawo
oraz żądane pole jest na prawo od ostatniej pozycji gońca (czyli ),
to okazuje się, że goniec mógł dotrzeć do w takiej samej liczbie ruchów
zmieniając czasem kierunek ruchu wcześniej, niż uderzając o brzeg ściany.
Ale jeżeli goniec dotarł poruszając się w prawo oraz ,
to trzeba wykonać jeden dodatkowy ruch, aby osiągnąć .
Można w taki sposób wyliczyć minimalną liczbę ruchów ,
jakie goniec musi wykonać,
oraz dokładną liczbę pojedyńczych ruchów ,
jakie goniec może pominąć przed uderzeniem w brzeg planszy.
Takie pojedyńcze ruchy można pomijać wśród pierwszych ruchów
(nie można się zatrzymywać przy ruchu, w którym goniec trafia do ostatniego wiersza),
więc liczba ścieżek wynosi tyle, co liczba sposobów pominięcia
pojedyńczych ruchów wśród pierwszych ruchów,
co jest równoważne rozłożenia piłek do pojemników,
czyli .
Należy być ostrożnym przy przypadkach brzegowych takich jak
zaczęcie lub skończenie przy brzegu planszy i kierunku dotarcia na żądane pole.
Trzeba też mieć na uwadzę to, że w podanym wzorze liczba jest rzędu ,
co jest duże, gdy jest małe.
Żeby poradzić sobie z tym problemem, wystarczy rozłożyć
na wyrażenie , co ma tylko czynników.
Daje to rozwiązanie w złożoności .
Król
Jeżeli , to aby wykonać jak najmniej ruchów,
w każdym ruchu król musi wskoczyć do wyższego rzędu.
Jeżeli , to jest analogicznie,
ale król za każdym razem musi przejść do kolejnej kolumny.
Bez straty ogólności załóżmy, że
-- drugi przypadek można rozwiązać analogicznie.
W takim razie król wykonuje ruchów i jest pewna dowolność
w poruszaniu się w lewo i prawo (jedyny warunek jest taki, że król ma trafić na pole )
i przy każdym ruchu porusza się w górę.
Można skorzystać z podejścia programowania dynamicznego.
Niech wynosi liczbę sposobów dotarcia z pola początkowego
na pole w -tej kolumnie w aktualnym wierszu.
Dla pierwszego wiersza zachodzi oraz dla .
Dla kolejnych zachodzi
zakładając, że przyjmuje wartości dla indeksów spoza przedziału .
Wynikiem jest dla ostatniego wiersza.
Daje to rozwiązanie w złożoności dla zapytania.
Rozszerzmy tablicę do tablicy ,
która dla danego wiersza oblicza liczbę sposobów dotarcia na pole w kolumnie
przy założeniu, że .
Pozwoli to spreprocessować odpowiedź dla wszystkich zapytań,
ale też umożliwi to zastosowanie pewnej techniki.
Analogicznie zachodzi
.
Daje to rozwiązanie w złożoności .
Zauważmy, że mając tablicę obliczającą liczbę ścieżek od pierwszego wiersza do -tego,
można policzyć tablicę od pierwszego wiersza do -tego.
Można to wykonać iterując się po pozycji, w której pionek będzie się znajdywał
w środkowym wierszu wśród tych wierszy,
a następnie przemnożyć ze sobą odpowiednie wartości tablicy ,
które tak naprawdę utrzymują liczbę sposobów, aby poruszyć się o wierszy do przodu.
Daje to wzór .
Dzięki sposobowi podobnego do szybkiego potęgowania,
można spreprocessować wyniki dla wszystkich zapytań w złożoności .
Aby przyśpieszyć rozwiązanie do , należy wykonać jeszcze kilka obserwacji
dotyczących wyliczania tablicy .
Można zacząć od wyliczenia wartości w czasie ,
co też od razu da wartości ,
ponieważ .
Dla zachodzi zależność
.
Analogicznie można wykazać, że dla oraz
zachodzi .
Wartości dla pozostałych par można już wtedy wyliczyć z symetryczności tablicy .
Wyliczając wtedy według konkretnej kolejności oraz korzystając z odpowiednich wzorków,
można wyliczyć całe w złożoności ,
co daje algorytm w złożoności .