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