Przeskocz do treści

Delta mi!

Informatyczny kącik olimpijski

Neon

Tomasz Idziaszek

o artykule ...

  • Publikacja w Delcie: sierpień 2011
  • Publikacja elektroniczna: 31-07-2011

O pewnym zadaniu z zeszłorocznego Obozu Naukowo-Treningowego im. A. Kreczmara.

Na przykład dla neonu supermarket stokrotka możemy uzyskać 17 różnych niepustych podciągów (skt, sra, srk, srt i ich krótsze podciągi) na 27 sposobów (np. srk możemy uzyskać na 2 sposoby). Wynik należy obliczyć modulo pewna liczba całkowita.

Zadanie rozwiążemy, używając metody programowania dynamicznego. Niech math i math  będą słowami neonu. Będziemy wypełniać prostokątną tablicę math  Dla math   math  oznaczmy przez math  liczbę sposobów, na jakie możemy zgasić litery w słowach math oraz math tak by pozostałe litery tworzyły ten sam (być może pusty) podciąg. Odpowiedzią do pierwszej części zadania jest, oczywiście, math

Jeśli math lub math (tzn. gdy jedno ze słów jest puste), to możemy utworzyć tylko pusty podciąg, zatem math

Załóżmy zatem, że math i spójrzmy na ostatnie litery słów math i math Załóżmy na początek, że są one równe, tzn.  math Rozważmy cztery przypadki w zależności od tego, czy zostawiamy te litery zapalone, czy też nie. Jeśli obie będą zapalone, to znaczy, że uzyskane podciągi powstają z rozszerzenia jednego z podciągów dla słów math i  math o dodatkową literę. To daje math  możliwości. Liczba możliwych podciągów w przypadku, gdy litera math zostanie zgaszona, wynosi math Analogicznie liczba podciągów, gdy litera math  zostanie zgaszona, wynosi math  Zauważmy, że te podciągi, które wystąpią w przypadku zgaszenia obu tych liter, uwzględniliśmy już w wyniku, z tym że policzyliśmy je dwukrotnie, należy zatem odjąć ich liczbę (jest ich math ). Ostatecznie dostajemy prostą zależność math

Przypadek math jest trochę łatwiejszy: nie możemy naraz zapalić liter math i math zatem math  Zajmiemy się teraz drugą częścią zadania: obliczeniem liczby różnych wspólnych podciągów. Na pierwszy rzut oka może się wydawać, że w tym przypadku będziemy musieli zastosować zupełnie inną strategię i potrzebna będzie jakaś struktura danych, która umożliwi nam wyłapywanie duplikatów. Okazuje się jednak, że i ten problem można rozwiązać za pomocą zaskakująco prostej zależności rekurencyjnej.

Niech math oznacza liczbę różnych wspólnych podciągów, które możemy utworzyć w słowach math  math Dla math lub math mamy, oczywiście, math Znów patrzymy na ostatnie litery słów. Niech math Okazuje się, że w tym przypadku mamy po prostu math a rozumowanie jest analogiczne jak dla tablicy math

Niech teraz math Każdy wspólny podciąg słów math i math należy do co najmniej jednego z dwóch zbiorów: zbioru math  tych różnych podciągów, które mogą powstać, gdy obie litery math  math są zapalone, oraz zbioru math tych różnych podciągów, które mogą powstać, gdy obie te litery są zgaszone. Zatem math  Zbiory math i math  mają po  math  elementów, pozostaje zatem obliczyć liczność ich części wspólnej math  Niech math oznacza największą liczbę dodatnią mniejszą niż math dla której math; analogicznie niech math będzie największą liczbą math dla której math Jeśli choć jedna z tych liczb nie istnieje, to math  W przeciwnym przypadku mamy math  i wówczas math

Pozostaje oszacować złożoność naszego algorytmu. Tablice math i math możemy obliczyć w czasie math  i takiej pamięci. Czas wypełniania tablic math  i math  to math  bezpośrednia realizacja da też taką złożoność pamięciową. Zauważmy jednak, że w przypadku tablicy math  możemy zastosować standardową sztuczkę: jeśli wypełniamy tablicę wierszami, wystarczy trzymać w pamięci jedynie aktualny ( math-ty) i ostatnio wypełniony ( math-szy) wiersz – nigdy bowiem nie odwołujemy się do komórek z wierszy o numerach mniejszych niż math Problem powstaje w przypadku tablicy math w której korzystamy z wiersza o numerze math Tu jednak radzimy sobie następująco: oprócz ostatnich dwóch wierszy trzymamy dodatkowo tablicę math W przypadku, gdy math uaktualniamy ją według wzoru math Dzięki temu mamy math Ostatecznie złożoność pamięciowa algorytmu wyniesie  math