Informatyczny kącik olimpijski
Magic
Tym razem omówimy zadanie z pierwszego dnia Pierwszej Olimpiady Informatycznej Juniorów (EJOI), która odbyła się w Sofii we wrześniu 2017 roku.
Zadanie. Dane jest słowo o długości
w którym występuje
różnych liter alfabetu angielskiego. Magicznym podsłowem nazywamy niepuste podsłowo (czyli spójny fragment słowa), które zawiera taką samą liczbę wystąpień każdej z
liter. Należy policzyć liczbę magicznych podsłów w słowie
Podsłowa, które są takie same, ale znajdują się na różnych pozycjach, uznajemy za różne.
Na potrzeby tego artykułu przyjmijmy dodatkowe założenie, że słowo zawiera wyłącznie litery ze zbioru
-początkowych liter alfabetu angielskiego. Aby uzyskać to założenie, wystarczy po wczytaniu słowa nadać literom nowe identyfikatory będące kolejnymi małymi literami alfabetu angielskiego.
Rozwiązanie .
Najprostsze rozwiązanie polega na rozpatrzeniu każdego podsłowa niezależnie. Aby sprawdzić, czy dane podsłowo jest magiczne, należy zliczyć liczbę wystąpień każdej litery w podsłowie, a następnie sprawdzić, czy wszystkie otrzymane wartości są równe.
Liczba wszystkich podsłów jest rzędu Sprawdzenie, czy podsłowo jest magiczne, wymaga
operacji. Zatem całe rozwiązanie wykonuje
operacji.
Rozwiązanie .
Powyższe rozwiązanie można w łatwy sposób przyspieszyć. Każdą z możliwych początkowych pozycji podsłowa słowa
rozpatrzymy niezależnie. Załóżmy, że rozpatrujemy początkową pozycję
Przeiterujemy wszystkie potencjalne końce podsłów zaczynających się na tej pozycji. Niech
będzie aktualnie rozpatrywanym podsłowem. Zauważmy, że aby policzyć liczbę wystąpień poszczególnych liter w tym podsłowie, wystarczy skorzystać z wyniku dla podsłowa
oraz zaktualizować go o wystąpienie litery
Zatem, dla ustalonego podsłowa potrafimy wyznaczyć te wartości w stałej liczbie operacji
Natomiast sprawdzenie, czy dane podsłowo jest magiczne, wymaga
operacji (należy sprawdzić, czy liczba wystąpień każdej z
liter jest taka sama). Zauważmy, że słowa, których długość nie jest podzielna przez
na pewno nie są magiczne. Zatem dla tych słów możemy pominąć fazę sprawdzania liczności poszczególnych liter. Słów, dla których wykonamy fazę sprawdzania liczności liter, jest
Sumarycznie wykonamy
operacji.
Przypadek dla
Przypadek dla jest trywialny. Każde podsłowo jest magiczne, zatem wynikiem jest
Przypadek dla
Najpierw słowo zamieńmy na ciąg liczb
Pierwszą literę słowa oraz wszystkie jej wystąpienia zamieńmy na
Pozostałe litery zamieńmy na
Zauważmy teraz, że każde magiczne podsłowo ma sumę
Policzmy sumy prefiksowe gdzie
dla
Zauważmy, że podsłowo
jest magiczne, jeśli
czyli jeśli
Wystarczy zatem policzyć liczbę par indeksów, dla których sumy prefiksowe są równe. W tym celu zliczmy wystąpienia elementów w ciągu
Niech
oznacza liczbę wystąpień
w ciągu
Wówczas wynikiem jest
Rozwiązanie wykonuje
operacji.
Rozwiązanie .
Zacznijmy od przypisania każdej literze jej unikalnego identyfikatora ze zbioru Następnie przekształćmy słowo
na ciąg liczb
zamieniając każdą literę na odpowiadający jej identyfikator. Np. słowo kajak możemy zamienić na ciąg
(a otrzymało identyfikator
k otrzymało identyfikator
zaś j otrzymało identyfikator
). Od teraz będziemy operowali na ciągu liczb naturalnych.
Niech:
będzie równe
jeśli na
-tej pozycji występuje wartość
oraz 0 w przeciwnym przypadku;
(liczba wystąpień wartości
na
-elementowym prefiksie ciągu
);
; (wektor reprezentuje liczbę wystąpień poszczególnych liter na
-elementowym prefiksie ciągu
);
Podsłowo jest magiczne, jeśli:
![v(y)− v(x − 1) = [c,c,...,c]](/math/temat/informatyka/algorytmy/2018/03/25/Magic/2x-ba0d8134b249c245d464a687317cd59d8653da2f-dm-33,33,33-FF,FF,FF.gif)
dla pewnego Po przekształceniach, które pozostawiam Czytelnikowi jako ćwiczenie, otrzymujemy równoważną definicję magicznego podsłowa:
![′ ′ v (y)− v (x −1) = [0,0,...,0]](/math/temat/informatyka/algorytmy/2018/03/25/Magic/4x-ba0d8134b249c245d464a687317cd59d8653da2f-dm-33,33,33-FF,FF,FF.gif)
Zatem każda taka para że
oznacza magiczne podsłowo. Policzmy zatem, ile jest par takich samych wektorów w ciągu
W tym celu posortujmy ten ciąg leksykograficznie. Wówczas wektory, które są równe, będą tworzyły spójny blok. Spośród bloku
takich samych wektorów można wybrać
par.
Obliczenie wektorów dla każdego
wymaga
operacji, zaś sortowanie
operacji. Zatem całe rozwiązania wykonuje
operacji.