Informatyczny kącik olimpijski
Palindromiczny podciąg
W tym miesiącu omówimy zadanie Palindromic Subsequence, które pojawiło się na konkursie SRM 708 na platformie Topcoder.
Palindrom to słowo, które nie zmienia się, gdy czytamy je od prawej do lewej, np. "kajak" lub "abba".
W zadaniu dane jest słowo o długości znaków. Dla każdego indeksu mamy znaleźć liczbę palindromicznych podciągów które zawierają -tą literę Wyniki należy wypisać modulo
Innymi słowy: dla ustalonego mamy sposobów na usunięcie niektórych z pozostałych liter w Interesuje nas liczba sposobów, dla których nieusunięte litery utworzą palindrom ( -ta litera jest, oczywiście, nieusunięta).
Zacznijmy od rozwiązania prostszego zadania - policzmy wszystkie palidromiczne podciągi w danym słowie.
Złym pomysłem jest przetwarzanie słowa od lewej do prawej, bo zapewne musielibyśmy dokładnie pamiętać już wybrany podciąg, by później wybrać te same litery w odwróconej kolejności (by powstał palindrom). Zamiast tego policzymy wynik dla każdego przedziału, zaczynając od przedziałów o długości
Niech oznacza liczbę palindromicznych podciągów przedziału (tzn. palindromicznych podciągów podsłowa złożonego z liter ). Szczegółem implementacyjnym jest decyzja, czy należy liczyć puste podciągi. Zacznijmy analizę od wstępnego wzoru (wcale nieprzypadkowo podobnego do wzoru na liczenie sum prefiksowych w macierzy!):
Dodajemy tu liczby palindromicznych podciągów w przedziałach i po czym odejmujemy te w przedziale bo policzyliśmy je podwójnie. Policzyliśmy w ten sposób wszystkie palindromiczne podciągi, które występują też w którymś z krótszych przedziałów. Pozostaje jednak nieuwzględniony przypadek, gdy podciąg zawiera -tą i -tą literę - taki podciąg nie występuje ani w ani w Skoro -ta i -ta litera są pierwszą i ostatnią literą w przedziale, muszą one być równe, by powstał palindrom. Jeśli tak rzeczywiście jest, to do powinniśmy jeszcze dodać bo do każdego z podciągów przedziału możemy teraz dodać -tą i -tą literę z przodu i z tyłu, co da nam nowy dłuższy palindrom.
Mówimy, że w palindromie pierwsza litera jest sparowana z ostatnią, druga z przedostatnią itd. Zastanówmy się, jak dla pary indeksów policzyć takie palindromiczne podciągi, które zawierają indeksy i a ponadto w nich te dwie litery są ze sobą sparowane. Musi zatem zachodzić równość a wzięte indeksy z przedziału muszą tworzyć palindromiczny podciąg. Takich podciągów jest dokładnie Pozostaje nam jeszcze uwzględnić liczbę możliwych zewnętrznych rozszerzeń, a więc policzyć liczbę takich wyborów, że litery wzięte na lewo od (te z mniejszymi indeksami) odpowiadają literom wziętym na prawo od Tę liczbę oznaczmy przez Za chwilę pokażemy, jak ją obliczać.
Niech oznacza liczbę palindromicznych podciągów, które zawierają indeksy z przedziałów oraz a także takich, że litery z są sparowane z tymi z (czyli te dwa przedziały zawierają po tyle samo wybranych liter). Podobnie jak do liczenia wartości możemy zacząć od rekurencyjnego wzoru:
po czym dodać jeśli Uwzględniamy tu podciągi, które zawierają indeksy z i oraz podciągi, które zawierają indeksy z i Do obu tych grup podciągów należą takie, które zawierają indeksy z i więc takie policzyliśmy dwukrotnie, co musimy odjąć. Dodatkowo, jeśli litery i są równe, uwzględniamy podciągi, które je zawierają.
Zauważmy, że w każdym palindromicznym podciągu zawierającym -tą literę, litera ta jest sparowana z dokładnie jedną literą, która musi być, oczywiście, równa By znaleźć wynik zadania dla wystarczy więc przeiterować wszystkie indeksy ( i ) i zsumować iloczyny (taki iloczyn jest równy liczbie palindromicznych podciągów, w których indeksy i są sparowane).
Zarówno obliczenie tablic i jak i końcowe iterowanie par indeksów, ma złożoność czasową Tablice i mają rozmiar kwadratowy. Czytelnikowi Z Ograniczoną Pamięcią pozostawiamy zastanowienie się nad implementacją w pamięci liniowej.