Processing math: 0%

poniedziałek, 5 sierpnia 2013

5139. Nieosiągalna liczba [WZP09_2C]

Zadanie:
https://pl.spoj.com/problems/WZP09_2C

Skrócony opis problemu:
Mając dane n oraz n liczb posortowanych rosnąco i mamy wypisać najmniejszą liczbę, której nie da się otrzymać poprzez zsumowanie dowolnej ilości danych liczb.



Rozwiązanie naiwne:
Generujemy wszystkie podciągi danego ciągu, a następnie każdy sumujemy i zapisujemy w tablicy tab[suma] = 1 (na początku tablica jest wyzerowana). Następnie idziemy od początku tablicy (indeksu 1) i jeśli natrafimy na wartość 0, to wypisujemy indeks i kończymy przeszukiwanie.

Złożoność: O(2^n). Bo podciągów ciągu o długości n jest \sum_{i=1}^n \binom{n}{i} = 2^n-1.

Rozwiązanie sprytniejsze:
Możemy skorzystać z faktu, że ciąg jest posortowany. Idziemy zatem od najmniejszego elementu ciągu i porównujemy go z tymczasową zmienną a, w której jest najmniejsza liczba, której nie umiemy zbudować. Na początku a=1. Jeżeli otrzymamy liczbę x, która jest większa od naszego a w danym momencie, to znaczy, że a jest naszym ostatecznym wynikiem. Czemu? W danym momencie w a jest wartość, której nie możemy osiągnąć. Do zbudowania a potrzebny nam więc element mniejszy lub równy a - jeśli otrzymamy element większy, to (przy założeniu, że wszystkie liczby z wejścia są dodatnie) co byśmy do niego nie dodali nie otrzymamy a. A jeśli x będzie mniejsze lub równe a to zwiększamy nasze a o x. Oznacza to, że umiemy osiągnąć a+x-1, jako że wcześniej umieliśmy osiągnąć a-1. Ale czy na pewno umiemy osiągnąć każdą liczbę od a do a+x-1? Tak, bo wtedy umieliśmy osiągnąć każdą od 1 do a-1. Więc jeśli chcemy np. osiągnąć a to bierzemy x i pozostaje nam dodać do niego a-x, a to zawiera się w przedziale \left<1;a-1\right>.

Złożoność: O(n). Bo wczytujemy n elementów i dla każdego z nich wykonujemy stałą liczbę operacji.

Ostateczny algorytm:
int main()
{
    int n, x, a, b;
    
    get(n);
    a = 1; // najmniejsza liczba, której w danym momencie nie możemy osiągnąć
    b = 0; // flaga, że jeszcze nie znaleźliśmy liczby, której nie możemy zbudować; jeśli będzie niezerowe, to znaleźliśmy
    while(n--)
    {
        get(x);
        if(!b) // jeśli do tej pory wszystko mogliśmy zbudować
        {
            if(x > a)b = a; // jeśli x>a to zapisz, że nie możemy zbudować a
            a ;+= x;
        }
    }
    printf(b ? b : a); // jeśli b > 0 to nie możemy zbudować b, a jeśli b=0 to wynikiem jest suma wszystkich liczb powiększona o 1, czyli a
}

Brak komentarzy:

Prześlij komentarz