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