Marcin KubicaPaweł Wolff
Treść zadania, OpracowanieProgram wzorcowy


Łańcuch


Bajtocja nie zawsze była państwem demokratycznym. W jej historii były również czarne karty. Pewnego razu, generał Bajtelski - przywódca junty żelazną ręką rządzącej Bajtocją - postanowił zakończyć stan wojenny, trwający od momentu przejęcia władzy, i zwolnić więzionych działaczy opozycji. Nie chciał jednak uwolnić przywódcy opozycji Bajtazara. Postanowił przykuć go do murów więzienia za pomocą bajtockiego łańcucha. Bajtocki łańcuch składa się z połączonych ze sobą ogniw oraz przymocowanego do muru pręta. Choć ogniwa nie są połączone z prętem, to bardzo trudno jest je z niego zdjąć. - Generale, czemuś mnie przykuł do murów więzienia, miast uwolnić, jako to uczyniłeś z moimi kamratami! - wołał Bajtazar.
- Ależ Bajtazarze, wszak nie jesteś przykuty i z pewnością potrafisz sam zdjąć trzymające Cię ogniwa z pręta wystającego z murów więzienia. - przewrotnie stwierdził generał Bajtelski, po czym dodał - Uporaj się z tym jednak przed godziną cyfracyjną i nie dzwoń łańcuchami po nocy, gdyż w przeciwnym przypadku będę zmuszony wezwać funkcjonariuszy Cyfronicji Obywatelskiej. Pomóż Bajtazarowi!

Ponumerujmy kolejne ogniwa łańcucha liczbami 1, 2, ..., n. Ogniwa te możemy zakładać i zdejmować z pręta zgodnie z następującymi zasadami:

Zadanie

Napisz program, który:

Wejście

W pierwszym wierszu pliku tekstowego lan.in zapisano jedną dodatnią liczbę całkowitą n, 1 le n le 1,000. W drugim wierszu zapisano n liczb całkowitych o_1, o_2, dots, o_n ... pooddzielanych pojedynczymi odstępami. Jeśli oi=1, to ogniwo nr i jest założone na pręt, a jeśli oi=0, to jest z niego zdjęte.

Wyjście

Plik tekstowy lan.out powinien zawierać jedną liczbę całkowitą, równą minimalnej liczbie ruchów potrzebnych do zdjęcia wszystkich ogniw bajtockiego łańcucha z pręta.

Przykład

Dla pliku wejściowego lan.in
4
1 0 1 0
poprawną odpowiedzią jest plik wyjściowy lan.out
6

Analiza problemu

Wielu spośród czytelników zastanawia się zapewne, czy opisany w zadaniu bajtocki łańcuch istnieje w rzeczywistości. Otóż tak, jest to chińska łamigłówka przedstawiona na poniższym rysunku.
bimg(lanblue.eps)(Ba...

Niech o = (o1, o2, ..., on) i o' = (o'1, o'2, ..., o'n) będą dowolnymi ciągami (tej samej długości) opisującymi stany bajtockiego łańcucha. Oznaczmy przez d(o, o') minimalną liczbę ruchów potrzebnych do przekształcenia łańcucha opisywanego przez o w łańcuch opisywany przez o'. Zadanie sprowadza się do wyznaczenia d(o, (0, 0, ..., 0)) dla o będącego ciągiem z pliku wejściowego. Zanim powiemy jak można obliczyć tę wartość, zastanówmy się nad ogólnymi własnościami funkcji d.

Zauważmy, że dla każdego ciągu o mamy d(o, o) = 0, gdyż nie trzeba wykonywać żadnych ruchów, aby łańcuch pozostał bez zmian. Oczywiście dla o neq o' mamy d(o, o') > 0. Zauważmy też, że ruchy jakie możemy wykonywać są symetryczne, a więc dla dowolnych o i o' mamy d(o, o') = d(o', o). Ponadto, dla dowolnych o, o' i o'' zachodzi nierówność d(o, o'') le d(o, o'.... Jest tak dlatego, że d(o, o') + d(o', o'') jest minimalną liczbą ruchów potrzebnych do przekształcenia łańcucha opisywanego przez o w łańcuch opisywany przez o'', przy czym w trakcie tego przekształcenia, w pewnym momencie łańcuch jest opisywany przez o'. Wszystkie te własności sprawiają, że możemy traktować d jak odległość między różnymi konfiguracjami łańcucha, przy czym ostatnia z wymienionych własności odpowiada nierówności trójkąta.

Odległość d jest określona dla ciągów dowolnej długości. Zdjęcie lub założenie k-tego ogniwa może wymagać wkładania lub zdejmowania jedynie ogniw 1, 2, ..., k. Położenie ogniw o numerach większych od k nie ma znaczenia dla liczby ruchów potrzebnych do zdjęcia lub założenia k-tego ogniwa. Tak więc, dla dowolnych ciągów o, o' oraz r zachodzi d(o, o') = d(o cdot ... ( Symbol cdot oznacza operację sklejania ciągów. Dla uproszczenia, przez an będziemy oznaczać ciąg złożony z n elementów a, a^n = underbrace(a c.... ) Zastanówmy się ile wynosi d(0^n, 0^(n-1)cdot1), czyli ile ruchów należy wykonać, aby zdjąć n-te ogniwo, zakładając, że ogniwa 1, 2, ..., n-1 są zdjęte i takie mają pozostać. Otóż, żeby zdjąć n-te ogniwo, należy najpierw założyć ogniwo n-1 i zdjąć ogniwa 1, 2, ..., n-2. Następnie po zdjęciu n-tego ogniwa należy zdjąć również ogniwo n-1. Tak więc:


      begin(array)(...
Uzyskujemy więc równanie rekurencyjne:

      d(0^n, 0^(n-1...
Jak łatwo sprawdzić, rozwiązanie tego równania to:

      d(0^n, 0^(n-1...

Oznaczmy przez R(o) = d(o, 0n) oraz S(o) = d(o, 0^(n-1) ..., gdzie n jest długością ciągu o. Naszym celem jest wyznaczenie wzoru na R(o). Zauważmy, że zachodzą następujące zależności:


      begin(array)(...
Jeżeli ostatnie ogniwo jest założone, to żeby zdjąć wszystkie ogniwa musimy doprowadzić do konfiguracji, w której tylko ostatnie dwa ogniwa są założone, zdjąć ostatnie z nich, a następnie zdjąć przedostatnie:

      begin(array)(...
Podobnie, jeżeli ostatnie ogniwo jest zdjęte, a chcemy doprowadzić do konfiguracji, w której jedynie ostatnie ogniwo jest założone, to musimy doprowadzić do konfiguracji, w której jedynie przedostatnie ogniwo jest założone, założyć ostatnie ogniwo i zdjąć przedostatnie:

      begin(array)(...
Uzyskane zależności rekurencyjne mogą być już podstawą rozwiązania zadania. Możemy je jednak jeszcze uprościć. Zauważmy, że R(o) = S((o1, o2, ..., 1-on)). Tak więc:

      R(o) =
      ...
Oznaczmy przez p_i = (sum_(j=i)^n o..., czyli pi = 0, gdy wśród o_i, o_(i+1), dots, ... jest parzysta liczba jedynek, w przeciwnym przypadku pi = 1. Wówczas mamy:

      R(o) = sum_(i...
Wygodniej jednak jest zliczać jedynki od początku ciągu, a nie od jego końca. Oznaczmy więc przez p'_i = sum_(j=1)^i o.... Zauważmy, że p_i = (p'_n - p'_(i-.... Możemy więc wyrazić R(o) następującym wzorem:

      R (o) =
     ...
Ten wzór będzie podstawą naszego rozwiązania.

Rozwiązanie

Jak widać z analizy problemu, wynik może być bardzo dużą liczbą - może mieć nawet ponad 300 cyfr. Wymaga to zaimplementowania własnej arytmetyki. Przyjmujemy, że zostały zaimplementowane następujące operacje na "`dużych liczbach'': Wszystkie te operacje można zaimplementować w koszcie (czasowym i pamięciowym) O(n), gdzie n jest liczbą cyfr.
1{ Inicjacja zmiennych. }
2readln(we, n);
3dodawac := false;
4przypisz(wynik, 0);
5przypisz(potega2, 1);
6{ Sumowanie kolejnych elementów szeregu sum_(i=1)^n p'_(i-1).... }
7for i := 1 to n do begin
8    if dodawac then
9        dodaj(wynik, potega2);
10    dodaj(potega2, potega2);
11    read(we, o);
12    if o = 1 then
13        dodawac := not dodawac
14end;
15{ Obliczenie i zapisanie wyniku. }
16if dodawac then begin
17    dodajjeden(wynik);
18    odejmij(potega2, wynik);
19    zapiszwynik(wy, potega2)
20end end
21    zapiszwynik(wy, wynik);

W naszym rozwiązaniu będziemy używać następujących zmiennych. Pliki wejściowy i wyjściowy to odpowiednio we i wy. Zmienna n to liczba ogniw, o reprezentuje kolejne ogniwa. Zmienna logiczna dodawac reprezentuje kolejne wartości p'. Obliczany szereg wyliczamy na zmiennej wynik, równocześnie na zmiennej potega2 obliczamy kolejne potęgi dwójki. Używamy też pomocniczej zmiennej całkowitej i. Oto rozwiązanie:

Zauważmy, że jeśli n jest długością danego ciągu, to liczba cyfr w wyniku jest rzędu O(n), a liczba cyfr w największej obliczonej potędze 2 jest rzędu Theta(n). Tak więc złożoność pamięciowa programu jest rzędu Theta(n). Program ten wykonuje Theta(n) operacji, w tym operacje arytmetyczne na dużych liczbach. W rezultacie złożoność czasowa programu jest rzędu Theta(n^2).

Pełne rozwiązanie można znaleźć na załączonej dyskietce w pliku lan.pas.

Testy

Rozwiązania zawodników sprawdzano na 12 testach. Cztery z tych testów badały przypadki brzegowe: test nr 1 to łańcuch złożony z jednego założonego ogniwa, test nr 2 to trzy zdjęte ogniwa, test nr 8 to 100 ogniw, wszystkie założone, test nr 12 to 1\,000 ogniw i tylko ostatnie z nich jest założone. Pozostałe testy to różne testy losowe. Wielkości testów przedstawiono w poniższej tabelce.

begin(tabular)(|r|r|...