Informatyczny kącik olimpijski
Wieże
W tym kąciku zajmiemy się rozwiązaniem zadania pochodzącego z jednej z finałowych rund konkursu TopCoder Open 2010, o nazwie Shrooks on the Board.

Zadanie. Jesteśmy proszeni o obliczenie reszty
z dzielenia liczby poprawnych ustawień wież na planszy przez zadaną
liczbę pierwszą
Plansza jest prostokątna, ma
wierszy oraz
kolumn. W tym zadaniu wieże są nietypowe: atakują jedynie
pola znajdujące się w tym samym wierszu i do tego odległe o co najwyżej
pól. Poprawne ustawienie to takie, które zawiera co najmniej
jedną wieżę i żadna wieża nie atakuje innej.
Zauważmy na początek, że istnieje dokładnie jedno ustawienie, które
nie zawiera wież. Będziemy uznawali je za poprawne, a na końcu wynik
zmniejszymy o 1. Możemy więc ustawić dowolną liczbę wież w dowolny
sposób, byle się nie atakowały. Od tej pory problemy dla poszczególnych
wierszy są niezależne. Łatwo zauważyć, że jeżeli wieże w jednym wierszu
można ustawić na
sposobów, to ostatecznym wynikiem będzie
reszta z dzielenia liczby
przez
Do obliczenia tejże
reszty wystarczy znać resztę z dzielenia liczby
przez
; koszt
czasowy końcowego potęgowania to
Cały problem polega więc na wyznaczeniu wartości
Spróbujmy
najpierw wyprowadzić wzór rekurencyjny na
Mamy następujące
możliwości: albo pierwsze pole jest puste, a dalsza część planszy jest jakoś
zapełniona wieżami, co daje
poprawnych ustawień, albo też na
pierwszym polu stoi wieża, kolejne
pól jest pustych, a pozostałe są
jakoś zapełnione, co daje dodatkowe
ustawień. Ostatecznie
mamy, że
Pozostaje zaznaczyć, iż dla
przyjmujemy
Daje to prosty algorytm obliczający
w czasie
Inne rozwiązanie otrzymujemy, stosując standardową metodę obliczania wyrazów ciągu zadanego wzorem rekurencyjnym za pomocą szybkiego potęgowania macierzy, patrz artykuł Macierze oczami informatyka w Delcie 7/2009. Przypomnijmy tylko, że w metodzie tej przedstawiamy taki oto wektor

jako iloczyn pewnej macierzy
rozmiaru
i analogicznego wektora zapisanego dla
Wówczas zadanie
sprowadza się do obliczenia macierzy
co możemy wykonać
w czasie
Spróbujmy teraz podejść do problemu od innej strony. Pokażemy, że
sposobów ustawienia
wież w wierszu długości
jest tyle
samo, co wyborów
elementów spośród
elementów. Dla ustalenia uwagi przyjmijmy, że wieża zajmuje swoje
pole oraz
pól na prawo od niego. W takim razie możemy
skonstruować bijekcję między ustawieniami wież a wyborami elementów.
Mając dane ustawienie wież, po prostu usuwamy
pól na prawo
od każdej wieży poza ostatnią i otrzymujemy wybór
pól
spośród
pól. Odwrotnie, mając dany pewien wybór
elementów spośród
elementów, ustawiamy
wieże w polach odpowiadających tym elementom i po każdej (poza ostatnią)
dokładamy dodatkowo
wolnych pól.
Żądanych ustawień wież jest zatem
Oczywiście, musi
być
czyli

Aby obliczyć resztę z dzielenia
przez
wystarczy umieć
szybko obliczać reszty z dzielenia symboli Newtona przez
W tym celu
korzystamy z twierdzenia Lucasa, które orzeka, że jeśli
jest liczbą
pierwszą i
to
daje taką samą resztę z dzielenia
przez
co
Zauważmy teraz, że zarówno reszty
z dzielenia liczb
przez
jak i ich odwrotności
modulo
możemy obliczyć w czasie
– te drugie według
wzorów

Wówczas resztę z dzielenia
przez
obliczamy w czasie
stałym, natomiast
ponownie zapisujemy w postaci
i zaczynamy od początku. W ten sposób symbol Newtona
obliczamy
w czasie
Możemy więc obliczyć
wykonując
operacji. Można śmiało powiedzieć, że jest to
operacji, gdyż
a zadanie jest interesujące
tylko dla
Żadne z powyższych rozwiązań nie jest jeszcze satysfakcjonujące.
Aby uzyskać lepszy wynik, połączymy ostatnie dwa rozwiązania. Jeśli
to uruchamiamy rozwiązanie z mnożeniem macierzy,
a w przeciwnym przypadku rozwiązanie przez symbole Newtona. Ostatecznie,
całe zadanie rozwiązujemy w czasie
przy
zużyciu pamięci rzędu