Zgodnie z ogłoszeniem organizatorów II etap olimpiady odbędzie się w tym roku 15-17 lutego. Zawody odbędą się zdalnie, a do finałowego etapu zakwalifikuje się około 1 na 3~5 uczestników. Zauważyliśmy, że na przestrzeni poprzednich edycji olimpiady pewne tematy i “triki” powtarzają się o wiele częściej niż inne. Warto je znać i zagwarantować sobie wstęp na wymarzoną uczelnię, a może nawet wyjazd na międzynarodówkę.
Poniżej przedstawiamy te rzeczy i co trzeba o nich wiedzieć. Zachęcamy, żeby nauczyć się/powtórzyć poniższe tematy przed II etapem Olimpiady. Jeżeli nie masz dużo czasu, nie musisz implementować wszystkich zadań, ale gorąco zachęcamy, żeby co najmniej spróbować wymyślić rozwiązania.
Oferujemy Tutoring do olimpiad informatycznej, matematycznej oraz fizycznej z dawnymi laureatami i zwycięzcami olimpiad. Po zapisaniu się otrzymasz darmową lekcję, na której tutor pomoże Ci rozkminić czego jeszcze potrzebujesz nauczyć się przed olimpiadą. Ponadto Kompendium Meet IT stworzyli dla Ciebie medaliści olimpiad międzynarodowych i zwycięzcy olimpiad krajowych. Znajdziesz tam materiały, które pokrywają wszystkie najważniejsze tematy z jakimi możesz spotkać się na Olimpiadzie.
Drzewa przedziałowe to struktura danych, umożliwiająca wykonywanie operacji i odpowiadanie na zapytania o przedziały na ciągu liczb w czasie logarytmicznym od długości ciągu. Dzięki drzewom przedziałowym możemy liczyć sumy, maksima lub wartości innych funkcji na przedziałach w czasie O (log N). Warto znać wszystkie typy, w tym punkt-przedział, przedział-punkt, przedział-przedział.
Metodę gąsienicy należy stosować na jednowymiarowej tablicy, w której poszukujemy najdłuższego spójnego przedziału o pewnej własności lub rozważamy wszystkie przedziały o zadanej długości. Jeżeli umiemy sprowadzić oryginalny problem do “Znajdź najdłuższy spójny przedział, dla którego wartość pewnej nie malejącej funkcji nie przekracza zadanej stałej” należy spróbować rozwiązać je gąsienicą. Przykładem takiego zadania jest “Znajdź najdłuższy spójny przedział, dla którego suma wszystkich elementów jest mniejsza od zadanej stałej C”.
Zwróć uwagę, że metoda gąsienicy nie zadziała, jeżeli liczby w ciągu mogą być ujemne. (wtedy funkcja sumy może maleć). W takim wypadku można zastosować metodę gąsienicy aby obliczyć wartość funkcji dla wszystkich przedziałach o zadanej długości. W przypadku sumy zadanie to można wykonać prościej za pomocą sum prefiksowych. Natomiast jeżeli funkcją jest na przykład mediana zbioru liczb, problem staje się trudniejszy i można go rozwiązać za pomocą gąsienicy wspomaganej strukturą set z C++ (Jak?). Jeżeli nasze zadanie dodatkowo wymaga szybkiego znajdowania minimów lub maksimów na rozważanym przedziale należy dodatkowo użyć posortowanego stosu.
Silnie spójna składowa to taki zbiór wierzchołków grafu skierowanego, że z dowolnego jej wierzchołka możemy się dostać do dowolnego innego. Natomiast sortowanie topologiczne to sposób uporządkowania wierzchołków w grafie skierowanym bez cykli, w taki ciąg, aby wszystkie krawędzie były skierowane na prawo.
Często w zadaniach algorytmicznych, gdzie występują grafy skierowane, przydaje się najpierw podzielić je na SSS (jeżeli nie są acykliczne), a następnie posortować je topologicznie. Na tak posortowanym grafie można stosować programowanie dynamiczne, algorytmy zachłanne a nawet drzewa przedziałowe. Również, na tak posortowanym grafie czasem łatwiej jest dostrzec pewne kluczowe zależności.
Ukorzenione drzewa to struktura danych bardzo “przyjazna” dla rekurencji. Często przydatne jest przeiterowanie się po drzewie DFSem, licząc interesujący nas wynik dla każdego wierzchołka na podstawie wyników dla jego synów. W tym temacie warto powtórzyć najbardziej klasyczne problemy jak: obliczenie wielkości i głębokości wszystkich poddrzew, znalezienie najdłuższej ścieżki w całym drzewie i każdym poddrzewie, zliczanie sumy długości wszystkich ścieżek. Binsearch po wyniku może być tutaj często przydatny.
Często zadania wymagają od nas znalezienia najtańszego, najmniejszego, najszybszego rozwiązania. Jeżeli mamy takie zadanie warto zastanowić się czy taka optymalna strategia lub optymalny ciąg ma jakąś specjalną własność, lub da się ją zrealizować w prosty sposób. Często będziemy w stanie powiedzieć zdanie, które zaczyna się od “zawsze opłaca się nam / możemy ...”, “nigdy nie opłaca nam się/nie musimy ...”. Jeżeli szukamy podciągów lub ciągów, czasem też warto spojrzeć, kiedy taki optymalny ciąg można przedłużyć lub skrócić.
Tego typu spostrzeżenia można często zrealizować drzewem przedziałowym lub trzeba je wspomóc wyszukiwaniem binarnym. Jako że w tym przypadku trudno jest nauczyć się teorii, proponujemy skupić się na ćwiczeniu zadań.
Jeżeli dla pewnych liczb dodatnich to jedna z liczb jest równa co najwyżej . Dzięki temu spostrzeżeniu możemy rozwiązać wiele zadań w złożoności czasowej zamiast lub zamiast Stosowanie poniższych trików często nie prowadzi do rozwiązania wzorcowego, ale pozwala łatwo dobyć dużo punktów za trudne zadanie.
Często zadanie wymaga od nas operacji na zbiorze przedziałów. Czasami są one podane na wejściu, a czasami trudność zadania polega na “interpretacji geometrycznej” warunków na wejściu. Cudzysłów został użyty, ponieważ fakt czy interpretacja w 1D może być nazywa geometryczną jest dyskusyjny. Niezależnie od notacji, jeżeli mamy do czynienia ze zbiorem przedziałów powinniśmy rozważyć sortowanie ich (na przykład od lewej do prawej) po ich początkach bądź końcach a następnie przeglądanie ich w tej kolejności. W zależności od zadania będziemy musieli dodatkowo zastosować drzewo przedziałowe lub strukturę set z C++, aby szybko wykonywać wymagane operacje. Takie podejście nazywa się “zamiatanie”. Warto rozważyć również sortowanie końcowych i początkowych punktów przedziałów razem. Dzięki temu możemy kontrolować wszystkie “otwarte” przedziały i otwierać nowe, kiedy pojawi się początek przedziału a zamykać je, gdy pojawi się koniec. (Przy tym odpowiednio aktualizując odpowiednią strukturę danych).
Często zdarzają się na olimpiadzie zadania, które wymagają interpretacji pewnej sytuacji matematycznej jako grafu i zastosowanie na nim znanego algorytmu. W niedawnych edycjach olimpiady był to głównie DFS lub BFS a trudność zadania polegała na skonstruowaniu odpowiedniego grafu. Zdarzały się również inne warianty, jak znajdowanie minimalnych drzew rozpinających lub najkrótszych ścieżek, przy użyciu np. Dijkstry.
Haszowanie to prosty w implementacji algorytm heurystyczny, bardzo pomocny w rozwiązywaniu zadań na tekstach. Jego główna idea jest taka, żeby każdy string reprezentować za pomocą szczególnie obliczonej liczby, dzięki czemu możemy sprawdzać czy dwa stringi są takie same w czasie stałym i porównywać je leksykograficznie w czasie O (log n). Tę samą technikę można stosować również do innych obiektów matematycznych, na przykład w geometrii. Haszowanie nie zawsze prowadzi do optymalnego rozwiązania, natomiast często pozwala szybko zdobyć punkty, jeżeli nie mamy lepszego pomysłu na rozwiązanie.
To chyba najbardziej niedoceniane umiejętności przez zawodników, które są niezwykle ważne.
Jeżeli zaimplementujemy zadanie (nawet jeżeli było proste), należy je przetestować. Po pierwsze warto ułożyć na kartce kilka nietrywialnych testów i obejrzeć czy wszystkie policzone przez nasz program wartości są takie jakich się spodziewamy. Warto również przetestować kilka prostych testów maksymalnych rozmiarów. (na przykład: ciąg złożony ze wszystkich takich samych liczb, ciąg 1,2,3,4 ... N, graf, który jest ścieżką lub cyklem maksymalnej długości.) Najczęstszymi błędami są za małe tablice, nierozważenie przypadku brzegowego (np. kiedy wszystkie liczby są równe 0, lub graf jest pojedynczym wierzchołkiem) oraz zastosowanie w jednym miejscu zmiennej int zamiast long long.
Jeżeli mamy dużo czasu i chcemy go wykorzystać, żeby mieć pewność, że nasze rozwiązania otrzymują punkty, których się spodziewamy przydatne jest pisanie zaimplementowanie kilku prostych programów, które generują losowe dane do zadania. Następnie możemy skuteczniej przetestować nasze rozwiązanie porównując jego wyniki na wygenerowanych testach z prostszym do zaimplementowania rozwiązaniem.
Z drugiej strony prawie każde zadanie oferuje nam pulę łatwych do zdobycia punktów, na przykład za zaimplementowanie rozwiązania wykładniczego albo napisanie 2 pętli for sprawdzających wszystkie przypadki. Warto rozpocząć zawody od przeczytania wszystkich zadań a następnie zgarnięcia darmowych punktów. Nie jest to marnowanie czasu, ponieważ po pierwsze możemy nie mieć potem czasu złapać tych darmowych punktów, pisanie rozwiązania brutalnego pomaga nam dostrzec pewne zależności, których od razu nie widać oraz lepiej testować pod koniec zawodów. Pamiętaj, że zawodów II stopnia nie trzeba wygrywać, ale ich nie zepsuć.