Informatyczny kącik olimpijski
Little Elephant and Array
Zadanie. Dany jest -elementowy ciąg liczb naturalnych
oraz
zapytań. Każde zapytanie jest opisane za pomocą dwóch liczb naturalnych
gdzie
i brzmi: "Ile jest dobrych liczb w podsłowie
" Liczba
jest dobra, jeśli występuje dokładnie
razy. Przykładowo, wynikiem dla podkreślonego fragmentu
jest 2, gdyż dobrymi liczbami są 1 (występuje raz) oraz 3 (występuje trzy razy). Napisz program, który odpowiada na wszystkie
zapytań.
Niech oznacza podsłowo
Dowód. Rozwiązanie
W pierwszym podejściu każde zapytanie rozważymy niezależnie. Załóżmy, że szukamy wyniku dla Na początku zliczmy wystąpienia każdej wartości w tym podsłowie. Niech
będzie tablicą zliczającą i
oznacza liczbę wystąpień
Taka tablica ma rozmiar rzędu
i jej wygenerowanie zajmuje czas
Wówczas wynikiem jest liczba takich
że
co możemy obliczyć w czasie
przeglądając
Znalezienie odpowiedzi na jedno zapytanie zajmuje czas
więc całe rozwiązanie działa w czasie
Rozwiązanie
Zauważmy, że dobre liczby są nie większe niż Żadna liczba większa niż
nie może być dobra, ponieważ długość ciągu (liczba wszystkich wystąpień) wynosi
Zatem zliczanie wystąpień możemy ograniczyć do wartości nie większych niż
Teraz tablica zliczająca ma rozmiar
Odpowiedź na jedno zapytanie realizujemy w czasie
a całe rozwiązanie działa w czasie
Rozwiązanie
W tym podejściu, przed przystąpieniem do odpowiadania na zapytania, znajdziemy zbiór zawierający kandydatów na dobre liczby. Kandydatami mogą być tylko takie liczby
które występują przynajmniej
razy w całym ciągu. Tak jak wcześniej zauważyliśmy, możemy ograniczyć zliczanie do wartości nie większych niż
zatem
generujemy w czasie
Okazuje się, że wszystkich kandydatów jest nie więcej niż
Dlaczego? zawiera różne liczby, a jego suma jest nie większa niż
Zbiór ma największą moc, kiedy zawiera kolejne liczby
Niech
oznacza największą spośród nich. Oczywiście musi zachodzić
Wystarczy skorzystać ze standardowych metod rozwiązywania nierówności drugiego stopnia, aby otrzymać, że największe
wynosi
Dla każdej liczby ze zbioru
przygotujmy tablicę
gdzie
jeśli
lub
w przeciwnym przypadku. Intuicyjnie mówiąc, skopiowaliśmy ciąg
zamieniając wystąpienia
na 1, zaś pozostałe liczby na 0. Dodatkowo, niech
będzie tablicą sum prefiksowych
Wówczas sprawdzenie, czy
jest dobrą liczbą
sprowadza się do obliczenia
Za pomocą tak przygotowanej struktury danych potrafimy w czasie
sprawdzić, czy kandydat jest dobrą liczbą w podsłowie. Aby znaleźć dobre liczby w
wystarczy sprawdzić kandydatów ze zbioru
których jest
Wyznaczenie odpowiedzi na
zapytań zajmuje czas
Przygotowanie opisanych struktur danych zajmuje czas
zatem całe rozwiązanie działa w czasie
Rozwiązanie
W tym rozwiązaniu odpowiemy na zapytania offline. Oznacza to, że najpierw wczytamy wszystkie zapytania, następnie obliczymy wyniki (być może w innej kolejności niż ta podana na wejściu) i na końcu wypiszemy odpowiedzi w pierwotnej kolejności zapytań. Najpierw pogrupujmy zapytania według ich końców. Niech oznacza zapytania, których koniec znajduje się w
Przejdźmy teraz do przeglądania kolejnych elementów ciągu według rosnących indeksów (od 1 do
). Załóżmy, że rozważamy indeks
Jeśli wartość
występowała wcześniej przynajmniej
razy, to
jest dobrą liczbą dla niektórych fragmentów. Dokładniej, niech
oznacza najmniejszy taki indeks, że
zawiera
wystąpień
oraz niech
oznacza największy taki indeks, że
zawiera
wystąpień
Te indeksy możemy wyznaczyć, mając dla każdej wartości zapamiętane pozycje, na których ta wartość występuje. Wówczas dla każdego
fragment
również zawiera
jako dobrą liczbę.

Zachowajmy tę informację w tablicy Niech
zaś
Warto nadmienić, że jeśli wcześniej mieliśmy wyznaczony przedział
gdzie mogło zaczynać się podsłowo z dobrą wartością
to należy usunąć ten przedział przed nowym przypisaniem, czyli
oraz
Teraz możemy już odpowiedzieć na zapytania
Załóżmy, że rozważamy zapytanie
Wtedy wynikiem jest
Na
możemy rozpiąć drzewo przedziałowe, aby w czasie
obliczać sumę i aktualizować wartości.
Grupowanie zapytań według ich końca realizujemy w czasie jeśli wykorzystamy metodę zliczania. Odpowiedź na zapytanie odbywa się w czasie
co w sumie dla
zapytań daje
Wszystkie aktualizacje
zajmują
Całkowita złożoność czasowa rozwiązania wynosi