Kodowanie permutacji
Konkurs: II Olimpiada Informatyczna
Autor zadania: Krzysztof Diks
Pamięć: 32 mb
https://oi.edu.pl/pl/archive/oi/2/kod
Każdą permutację A = (a 1, …, a n) liczb 1, …, n można zakodować za pomocą ciągu
B = (b 1, …, b n), w którym b i jest równe liczbie wszystkich a j takich, że j < i oraz a j > a i , dla każdego i = 1, …, n .
Przykład
Kodem permutacji A = (1, 5, 2, 6, 4, 7, 3) jest ciąg B = (0, 0, 1, 0, 2, 0, 4).
Zadanie
Napisz program, który:
→ wczytuje z wejścia długość n i kolejne wyrazy ciągu liczb B ,
→ sprawdza, czy jest on kodem jakiejś permutacji liczb 1, …, n ,
→ jeżeli tak, to znajduje tę permutację i zapisuje ją na wyjściu, w przeciwnym przypadku zapisuje na wyjściu jedno słowo nie.
Wejście
W pierwszym wierszu wejścia jest zapisana dodatnia liczba całkowita n ⩽ 30 000. Jest to liczba wyrazów ciągu B . W każdym z kolejnych n wierszy jest zapisana jedna liczba całkowita nieujemna, nie większa niż 30 000. Jest to kolejny wyraz ciągu B
Wyjście
Na wyjściu należy zapisać:
→ w każdym z kolejnych n wierszy jeden wyraz permutacji A , której kodem jest dany ciąg B , zapisany na wejściu, albo
→ jedno słowo nie, jeśli ciąg B nie jest kodem żadnej permutacji.
krzysztof diks / kodowanie permutacji
odpowiedzią jest:
Rozwiązanie
Gdy, na kilka tygodni przed Akademickimi Mistrzostwami Polski w Programowaniu Zespołowym, Tomasz Idziaszek przedstawił mi swój pomysł na zadanie, nie wydało mi się ono nowe. Już w szkole podstawowej lub gimnazjum, na zajęciach z matematyki zmierzyłem się z problemem Jasia, który pije mieszaninę dwóch napojów i co chwila uzupełnia swoją szklankę. Tamta wersja była jednak znacznie prostsza: Jaś uzupełniał zawartość szklanki bodaj tylko trzy razy, a po ostatniej dolewce wypijał wszystko do dna. Teraz z pewnym wstydem muszę przyznać, że wówczas pracowicie dodawałem z każdą turą coraz bardziej zawiłe ułamki, by obliczać, ile napoju trafiało za każdym razem do żołądka Jasia. Nie wpadłem na to, by po prostu obliczyć, ile napoju wlał on do szklanki…
Niewiele lepiej poradziłem sobie z zadaniem o Bajtazarze, choć tym razem wiedziałem już, że obliczanie ilości wypijanych w każdym kroku napojów nie jest najlepszym pomysłem. A już na pewno prawidłowego wyniku nie da symulacja całego procesu z wykorzystaniem typów zmiennopozycyjnych (np. double) wbudowanych w większość języków programowania. Ich ograniczona dokładność nie pozwala na manipulowanie ułamkami, z którymi mamy do czynienia w tym zadaniu.
Jak zatem podejść do tego zadania? Sytuacja upraszcza się trochę, gdy odwrócimy postawione pytanie. Zamiast obliczać, ile herbaty i mleka wypija za każdym razem Bajtazar, zastanówmy się, jakiej części dolanych napojów nie wypije. Innymi słowy, skupmy się na obliczeniu końcowej zawartości filiżanki. Skoro wiemy, ile filiżanek każdego z napojów Bajtazar dolał w trakcie ceremonii, to te informacje wystarczą nam do udzielenia odpowiedzi. Dodatkowo, żeby uniknąć operowania na ułamkach, załóżmy, że filiżanka ma pojemność 2n + 1 mililitrów i na początku jest w niej 2n mililitrów mleka i tyleż samo herbaty.
Skupmy się na sytuacji, w której w pierwszej dolewce Bajtazar dodaje 2n mililitrów herbaty. Zastanówmy się teraz, jak dużo tej herbaty dotrwa do samego końca ceremonii. W drugiej kolejce Bajtazar wypije połowę herbaty z tej dolewki, czyli zostanie jej 2n − 1 mililitrów; po trzeciej kolejce zostanie 2n − 2 i tak dalej. Po n kolejkach, czyli n − 1 rozcieńczeniach, w filiżance będą więc 2 mililitry pochodzące z pierwszej dolewki.
Druga dolewka będzie rozcieńczana n − 2 razy, zatem zdecyduje o 4 mililitrach ostatecznej zawartości filiżanki. Ogólnie, z i -tej dolewki dotrwa w filiżance do końca ceremonii 2i mililitrów. Oprócz tego, w filiżance pozostanie 1 mililitr herbaty oraz 1 mililitr mleka, które trafiły do niej na samym początku ceremonii.
Niech φ będzie minimalnym kątem, jaki wektor z S tworzy z dodatnią
częścią półosi x . Niech v = (x ,y ) będzie dowolnym z wektorów, które uzyskują
ten kąt. Analogicznie definiujemy φ + i v + = (x +,y+) dla S + (patrz rys. 1). Poniższy lemat pokazuje związek pomiędzy pytaniem, na które chcemy odpowiedzieć, a sumą kątów φ i φ +
Lemat 1. Następujące trzy warunki są równoważne:
→ φ + φ + < 180°, → istnieje dodatnia liczba całkowita a , taka że wektor (a , 0) może być uzyskany jako suma wektorów ze zbioru S ∪ S +, → x + · y + x · y+ > 0.
Dowód. Mówimy, że wektor v jest nieujemną kombinacją wektorów v 1, …, v k , jeśli v = ∑k i =1 a i v i dla pewnych nieujemnych liczb rzeczywistych a i . Wprowadźmy również oznaczenie w = ( y ) · v + + y+ ·
.
y
y
Rysunek 2: Po lewej: ilustracja sytuacji dla φ + φ + ⩾ 180°, szary obszar odpowiada nieujemnym kombinacjom wektorów z S. Po prawej: ilustracja sytuacji dla φ + φ + < 180°, szary obszar odpowiada nieujemnym kombinacjom wektorów {v , v +}.
Rozważmy przypadek φ + φ + ⩾ 180° (patrz rys. 2). W tym przypadku żaden punkt na dodatniej półosi x nie jest nieujemną kombinacją wektorów z S ∪ S +
onak / superskoczek
Wszystkie nieujemne kombinacje leżą w wycinku płaszczyzny ograniczonym przez wektory v i v +, rozciągającym się od v do v + zgodnie z kierunkiem ruchu wskazówek zegara. Dlatego nie jest możliwe, aby dotrzeć na dodatnią połowę osi x przez dodawanie wektorów z S ∪ S +. Ponadto, ponieważ wektor w jest nieujemną kombinacją v i v +, zachodzi x + · y + x · y+ ⩽ 0.
Rozważmy teraz przypadek, gdy φ + φ + < 180°. Zauważmy, że wektor w jest nieujemną kombinacją v i v + z dodatnimi całkowitymi współczynnikami, co oznacza, że wektor w może być wyrażony jako suma skończonego ciągu złożonego z wektorów v i v +. Ponieważ kąt pomiędzy v i v + nie wynosi 180° , wektory te nie są współliniowe i w ≠ (0, 0). Co więcej, wszystkie nieujemne kombinacje v i v + znajdują się wewnątrz wycinka płaszczyzny ograniczonego przez v i v +, rozpościerającego się zgodnie z kierunkiem ruchu wskazówek zegara od v + do v . To oznacza, że żaden punkt na ujemnej połowie osi x nie jest nieujemną kombinacją v i v +. Zatem x + · y + x · y+, czyli pierwsza współrzędna wektora w, jest dodatnia, co kończy dowód. □
Zarówno v +, jak i v mogą być łatwo wyznaczone w czasie liniowym. Bez utraty ogólności, ponieważ oba przypadki są symetryczne, skupmy się na wyznaczeniu v +. Rozważmy dwa wektory u = (x u , y u) i w = (x w, y w ) ze zbioru S + Kąt między u a dodatnią półosią x jest mniejszy niż kąt między w a dodatnią półosią x wtedy i tylko wtedy, gdy x u/y u > x w/y w. To wynika z własności funkcji cotangens i może być użyte do porównania pary wektorów z S + w czasie stałym. Zgodnie z Lematem 1 wystarczy na końcu obliczyć znak wyrażenia x + · y + x · y+, aby wyznaczyć poszukiwaną odpowiedź.
Osiowa zupełność a odwracalność
Udowodnimy teraz, że jeśli S jest osiowo zupełny, to każdy ruch superskoczka można odwrócić. Ta własność jest przydatna w drugiej części naszego algorytmu, gdzie sprawdzamy zupełność zbioru osiowo zupełnego.
Lemat 2. Jeśli zbiór S je st osiowo zupełny, to jest odwracalny.
Dowód. Z definicji osiowej zupełności wynika, że istnieją wektory (a , 0), ( b, 0), (0, c ) i (0, d ), takie że a , b, c , d > 0 i każdy z nich może być wyrażony jako suma skończonego ciągu wektorów ze zbioru S . Rozważmy dowolny wektor v = (v x , v y ) z S . Wystarczy pokazać, że v może być wyrażony jako suma skończonej liczby wektorów z S . Jeśli v = (0, 0), to twierdzenie jest prawdziwe w sposób trywialny. Dlatego w pozostałej części dowodu zakładamy, że v ≠ (0, 0).
Rozważmy wektor (w x , 0), gdzie w x równa się a , jeśli v x < 0, lub b w przeciwnym przypadku. Analogicznie rozważmy wektor (0, w y ), gdzie w y równa
Niech φ będzie minimalnym kątem, jaki wektor z S tworzy z dodatnią
częścią półosi x . Niech v = (x ,y ) będzie dowolnym z wektorów, które uzyskują
ten kąt. Analogicznie definiujemy φ + i v + = (x +,y+) dla S + (patrz rys. 1). Poniższy lemat pokazuje związek pomiędzy pytaniem, na które chcemy odpowiedzieć, a sumą kątów φ i φ +
Lemat 1. Następujące trzy warunki są równoważne:
→ φ + φ + < 180°, → istnieje dodatnia liczba całkowita a , taka że wektor (a , 0) może być uzyskany jako suma wektorów ze zbioru S ∪ S +, → x + · y + x · y+ > 0.
Dowód. Mówimy, że wektor v jest nieujemną kombinacją wektorów v 1, …, v k , jeśli v = ∑k i =1 a i v i dla pewnych nieujemnych liczb rzeczywistych a i . Wprowadźmy również oznaczenie w = ( y ) · v + + y+ ·
.
y
y
Rysunek 2: Po lewej: ilustracja sytuacji dla φ + φ + ⩾ 180°, szary obszar odpowiada nieujemnym kombinacjom wektorów z S. Po prawej: ilustracja sytuacji dla φ + φ + < 180°, szary obszar odpowiada nieujemnym kombinacjom wektorów {v , v +}.
Rozważmy przypadek φ + φ + ⩾ 180° (patrz rys. 2). W tym przypadku żaden punkt na dodatniej półosi x nie jest nieujemną kombinacją wektorów z S ∪ S +
onak / superskoczek
Wszystkie nieujemne kombinacje leżą w wycinku płaszczyzny ograniczonym przez wektory v i v +, rozciągającym się od v do v + zgodnie z kierunkiem ruchu wskazówek zegara. Dlatego nie jest możliwe, aby dotrzeć na dodatnią połowę osi x przez dodawanie wektorów z S ∪ S +. Ponadto, ponieważ wektor w jest nieujemną kombinacją v i v +, zachodzi x + · y + x · y+ ⩽ 0.
Rozważmy teraz przypadek, gdy φ + φ + < 180°. Zauważmy, że wektor w jest nieujemną kombinacją v i v + z dodatnimi całkowitymi współczynnikami, co oznacza, że wektor w może być wyrażony jako suma skończonego ciągu złożonego z wektorów v i v +. Ponieważ kąt pomiędzy v i v + nie wynosi 180° , wektory te nie są współliniowe i w ≠ (0, 0). Co więcej, wszystkie nieujemne kombinacje v i v + znajdują się wewnątrz wycinka płaszczyzny ograniczonego przez v i v +, rozpościerającego się zgodnie z kierunkiem ruchu wskazówek zegara od v + do v . To oznacza, że żaden punkt na ujemnej połowie osi x nie jest nieujemną kombinacją v i v +. Zatem x + · y + x · y+, czyli pierwsza współrzędna wektora w, jest dodatnia, co kończy dowód. □
Zarówno v +, jak i v mogą być łatwo wyznaczone w czasie liniowym. Bez utraty ogólności, ponieważ oba przypadki są symetryczne, skupmy się na wyznaczeniu v +. Rozważmy dwa wektory u = (x u , y u) i w = (x w, y w ) ze zbioru S + Kąt między u a dodatnią półosią x jest mniejszy niż kąt między w a dodatnią półosią x wtedy i tylko wtedy, gdy x u/y u > x w/y w. To wynika z własności funkcji cotangens i może być użyte do porównania pary wektorów z S + w czasie stałym. Zgodnie z Lematem 1 wystarczy na końcu obliczyć znak wyrażenia x + · y + x · y+, aby wyznaczyć poszukiwaną odpowiedź.
Osiowa zupełność a odwracalność
Udowodnimy teraz, że jeśli S jest osiowo zupełny, to każdy ruch superskoczka można odwrócić. Ta własność jest przydatna w drugiej części naszego algorytmu, gdzie sprawdzamy zupełność zbioru osiowo zupełnego.
Lemat 2. Jeśli zbiór S je st osiowo zupełny, to jest odwracalny.
Dowód. Z definicji osiowej zupełności wynika, że istnieją wektory (a , 0), ( b, 0), (0, c ) i (0, d ), takie że a , b, c , d > 0 i każdy z nich może być wyrażony jako suma skończonego ciągu wektorów ze zbioru S . Rozważmy dowolny wektor v = (v x , v y ) z S . Wystarczy pokazać, że v może być wyrażony jako suma skończonej liczby wektorów z S . Jeśli v = (0, 0), to twierdzenie jest prawdziwe w sposób trywialny. Dlatego w pozostałej części dowodu zakładamy, że v ≠ (0, 0).
Rozważmy wektor (w x , 0), gdzie w x równa się a , jeśli v x < 0, lub b w przeciwnym przypadku. Analogicznie rozważmy wektor (0, w y ), gdzie w y równa