Mój problem. Biorąc pod uwagę, , chcę policzyć ważny multisets . Multiset jest ważny, jeślin
- Suma elementów wynosi , iS
S nn - Każdy numer od do może być wyrażona jednoznacznie jako sumę niektórych elementów .1
1 nn S.S
Przykład.
Na przykład, jeśli to są poprawne.n = 5
Jednak jest niepoprawny, ponieważ 2 może być utworzone zarówno przez i (tzn. 2 można wyrazić jako oba i ), więc drugi warunek nie obowiązuje. Podobnie 3 mogą być utworzone przez i .S = { 1 , 1 , 1 , 2 }
S = { 1 , 2 , 4
Od dłuższego czasu próbowałem znaleźć dobry algorytm dla tego problemu, ale nie mogę go rozwiązać. Pochodzi z codechef . Widziałem niektóre z przesłanych rozwiązań, ale nadal nie mogłem zrozumieć logiki rozwiązania problemu. UWAGA: Limit czasu na pytanie wynosi 10 sekund, an < 10 9
W przypadku notacji jeśli , co oznacza, że występuje razy w multiset S.S = { ( a 1 , c 1 ) , ( a 2 , c 2 ) . . . }
Do tej pory wyciągnąłem pewne wnioski
- Pierwszym elementem wymaganego sortowanego multisetu powinna być1
1 - Niech będzie zbiorem następujących dwóch właściwości, a następnieS = { 1 , a 2 ⋯ a k } | a 1 ≤ a 2 ⋯ ≤ a k
S.= { 1 , a2)⋯ ak} | za1≤ a2)⋯ ≤ ak ∀ r < k a r + 1 = a r lub ( ∑ r i = 0 a i ) + 1∀ r < k a r + 1= ar lub ( ∑ri = 0zaja)+1 - Niech , gdzie występuje razy, podąża za wymaganymi właściwościami, a następnie z powyższego wniosku możemy stwierdzić, że i jeśli .
Dowód:S = { ( 1 , c 1 ) , ( a 2 , c 2 ) ⋯ ( a k , c k ) } | a 1 ≤ a 2 ⋯ ≤ a k a i c i ∀ i a i | n + 1 a i | a j j > i a i + 1 =
S={(1,c1),(a2,c2)⋯(ak,ck)}|a1≤a2⋯≤ak ai doja ∀ i a ja| n+1 zaja| zajot j > i
( a i c i + a i - 1 ) + 1 ⇒ a i | a i + 1zai+1=(aici+ai−1)+1⇒ai|ai+1 - Rozważmy teraz tj. Wszystkie kolejne liczby po 1 będą wielokrotnością . Niech więc będzie liczbą takich multisetów możliwych, a następnie gdzie sumuję wszystkie możliwe liczby ( ). Innymi słowyS = { 1 , 1 ⋯ 1 ⏟ d - 1 , d , d ⋯ d , d m 1 , d m 1 ⋯ d m 1 , d m 2 , d m 2 ⋯ d m 2 , ⋯ } d f ( n ) f ( n ) = ∑ d | n + 1
S.={1,1⋯1d−1,d,d⋯d,dm1,dm1⋯dm1,dm2,dm2⋯dm2,⋯} d f(n) , d ≠ 1 f( n - ( d - 1 )d )1′s=d-1f(n-1)=g(n)=∑d| n,d≠ng(d)f(n)=∑d|n+1,d≠1f(n−(d−1)d) 1′s =d−1 f(n−1)=g(n)=∑d|n,d≠ng(d)
Wreszcie mój problem został zredukowany do tego - znajdź w wydajny sposób, aby nie przekroczył limitu czasu.g ( n )
źródło
Odpowiedzi:
Oto, co robi najszybsze rozwiązanie . Rzeczywiście oblicza twoją funkcję g ( n ) = ∑ d ∣ n d < n g ( d ) ,g ( 1 ) = 1. Biorąc pod uwagę n , uwzględniamy go (patrz poniżej), a następnie obliczamy wszystkie współczynniki (patrz poniżej) f 1 , … , f m w takiej kolejności, że f i | f j oznacza i ≤ j (właściwość P). Teraz obliczamy g według wzoru, przeglądając czynniki w podanej kolejności. Właściwość P zapewnia, że obliczając g ( d ) , obliczaliśmy już g ( e ) dla wszystkich nietrywialnych czynników e
Mówiąc bardziej szczegółowo, idziemy nad czynnikami w porządku, a dla każdego czynnika f I spotykamy wszystkich swoich nietrywialnych czynników o sprawdzenie, które z f 1 , ... , f I - 1 podziały f I .fi f1,…,fi−1 fi
Faktoring: Wstępne przetwarzanie: sporządzamy listę wszystkich liczb pierwszych poniżej 10 9 za pomocą sita Eratosthenes. Biorąc pod uwagę n , po prostu używamy podziału próbnego.109 n
Generowanie wszystkich czynników: Odbywa się to rekurencyjnie. Załóżmy, że n = p k 1 1 ⋯ p k t t . Uruchamiamy t zagnieżdżonych pętli l 1 ∈ { 0 , … , k 1 } , … , l t ∈ { 0 , … , k t } i wyprowadzamy p l 1 1 ⋯ p l t t . Możesz udowodnić, że właściwość P jest indukcyjna.n=pk11⋯pktt t l1∈{0,…,k1},…,lt∈{0,…,kt} pl11⋯pltt
Optymalizacja: Ponieważ program działa na kilku wejściach, możemy wykorzystać memoizację, aby zaoszczędzić czas na różnych wejściach. Mamy tylko memoize małe wartości (do 10 5 ), a to pozwala nam na przechowywanie wszystkich memoized wartości w tablicy. Tablica jest inicjowana zerami, dzięki czemu możemy stwierdzić, które wartości są już znane (ponieważ wszystkie obliczone wartości są dodatnie).105
Jeśli pierwsza faktoryzacja n + 1 wynosi p k 1 1 , … , p k t t , to f ( n ) zależy tylko od ( k 1 , … , k t ) , a tak naprawdę tylko od posortowanej wersji tego wektora . Każda liczba poniżej 10 9 ma najwyżej 29 czynników pierwszych (z powtórzeniem), a ponieważ p ( 29 ) = 4565 , wydaje się, że można obliczyć fn+1 pk11,…,pktt f(n) (k1,…,kt) 109 29 p(29)=4565 f (a raczej g ) dla nich wszystkich, rekurencyjnie. To rozwiązanie mogłoby być szybsze, gdyby było wiele różnych danych wejściowych; w tej chwili jest ich najwyżej 10 .g 10
Możliwe jest również, że ta funkcja, odwzorowująca partycje na odpowiednie g , ma jawną formę analityczną. Na przykład g ( p k ) = 2 k - 1 , g ( p 1 … p t ) podano w A000670 , a g ( p 2 1 p 2 … p t ) podano w A005649 lub A172109 .g g(pk)=2k−1 g(p1…pt) g(p21p2…pt)
źródło
OK, więc masz relację powtarzalności dla g ( ⋅ ) (patrz koniec pytania).g(⋅)
W tym momencie wydaje się, że naturalnym podejściem byłoby zapisanie algorytmu rekurencyjnego do obliczenia g ( n ) i zastosowanie zapamiętywania, aby nie obliczać g ( i ) więcej niż raz. Innymi słowy, obliczając g ( i ) , przechowujesz go w tabeli skrótów, która odwzorowuje i ↦ g ( i ) ; jeśli chcesz ponownie poznać g ( i ) w przyszłości, możesz to sprawdzić w tabeli skrótów.g(n) g(i) g(i) i↦g(i) g(i)
Wymaga to faktorowania n , ale istnieją wydajne algorytmy faktorowania n, gdy n ≤ 10 9 .n n n≤109
Możesz także poszukać sekwencji g ( 1 ) , g ( 2 ) , g ( 3 ) , g ( 4 ) , g ( 5 ) , … w Encyklopedii Sekwencji Całkowitych On-Line . Jeśli znajdziesz sekwencję w ich encyklopedii, czasem dostarczą one dodatkowych pomocnych informacji (np. Wydajnych algorytmów do obliczania sekwencji). To wprawdzie może zabrać zabawę.g(1),g(2),g(3),g(4),g(5),…
źródło
Oto wskazówka na początek. Zastosuj standardowe algorytmy programowania dynamicznego do wyliczenia zestawu partycji liczb całkowitych i dodaj logikę, aby sprawdzić, który z nich pozwala na unikalne dokonywanie zmian poprzez iteracyjne sprawdzanie wszystkich sum, wprowadzanie zmian i weryfikowanie niepowtarzalności.
W nieco bardziej szczegółowo: Załóżmy, że masz multiset S . Biorąc pod uwagę liczbę i o wartości 1 ≤ i ≤ n , w jaki sposób można zidentyfikować podwielokrotność S, która sumuje się do i ? Jak mogłeś sprawdzić, czy ten subultiset jest wyjątkowy? Spróbuj dostosować standardowe techniki programowania dynamicznego do wprowadzania zmian . (Zobacz także to pytanie .)S i 1≤i≤n S i
Biorąc pod uwagę multiset S , jak możesz sprawdzić, czy spełnia on drugi warunek, tj. Czy każda liczba od 1 do n może być jednoznacznie wyrażona jako suma subultiset S (unikalny warunek zmiany)? To powinno być dość łatwe, jeśli rozwiązałeś poprzedni.S n S
niech P ( n ) oznacza listę multisets, które spełniają oba warunki. Jeśli znasz P ( 1 ) , P ( 2 ) , … , P ( n ) , jak możesz wykorzystać te informacje do skonstruowania P ( n + 1 ) ? Tutaj możesz chcieć dostosować standardowe techniki programowania dynamicznego do wyliczania partycji liczb całkowitych.P(n) P(1),P(2),…,P(n) P(n+1)
Oto podejście, które prawdopodobnie będzie lepsze.
Załóżmy, że S to zbiór, który spełnia oba warunki (dla n ). Jak możemy go rozszerzyć, aby uzyskać wielosekcyjny T, który ma jeszcze jeden element? Innymi słowy, w jaki sposób możemy zidentyfikować wszystkie sposoby dodania jeszcze jednego elementu do S , aby uzyskać nowy wielosekcyjny T, który spełnia oba warunki (dla niektórych n ′ )?S n T S T n′
Odpowiedź: jeśli x można wyrazić jako sumę niektórych elementów S , to nie ma sensu dodawać go do S : spowodowałoby to, że T naruszyłby warunek wyjątkowości. Możemy więc wyliczyć wszystkie liczby całkowite x , których nie można wyrazić jako sumę niektórych elementów S ; każdy z nich jest czymś, co można potencjalnie dodać do S, aby uzyskać nowy wielosetowy T , który spełni oba warunki (dla niektórych innych n ).x S S T x S S T n
Ponadto możliwe jest wyliczenie, które liczby całkowite mogą być wyrażone jako suma niektórych elementów S , a które nie, za pomocą programowania dynamicznego. Budujesz dwuwymiarową tablicę A [ 1 … | S | , 1 ... n ] Wartości zmiennych, w których [ i , j ] jest prawdziwe, czy nie jest sposobem wyrażania całkowitą j jako sumę niektóre z pierwszych ı elementów S (tylko pierwszy ı elementów S kwalifikują się do być użyte; gdzie SS A[1…|S|,1…n] A[i,j] j i S i S S zostały sortowane, więc S = { y 1 , y 2 , ... , s k } , a s 1 ≤ s 2 ≤ ⋯ ≤ y k ). Zauważ, że A [ i , j ] może być obliczane przy użyciu wartości A [ 1 … i - 1 , 1 … j - 1 ] : w szczególności A [ i , j ]S={s1,s2,…,sk} s1≤s2≤⋯≤sk A[i,j] A[1…i−1,1…j−1] = A [ i - 1 , j ] ∨ A [ i - 1 , j - s i ] jeśli j > s i lub A [ i , j ] = A [ i - 1 , j ] w przeciwnym razie. To pozwala nam zidentyfikować wszystkie numery, które są kandydatami do doliczone do S .A[i,j]=A[i−1,j]∨A[i−1,j−si] j>si A[i,j]=A[i−1,j] S
Następnie dla każdego rozszerzenia kandydat T z S (otrzymanego przez dodanie jednego elementu do S ), chcemy sprawdzić, czy T spełnia oba warunki. Niech N oznacza sumę składników S , a n ' suma elementów T . Musimy sprawdzić, czy każdą liczbę całkowitą z zakresu n + 1 , n + 2 , … , n ′ można wyrazić jako sumę niektórych elementów TT S S T n S n′ T n+1,n+2,…,n′ T . To również można rozwiązać za pomocą programowania dynamicznego, przy użyciu standardowych algorytmów do wprowadzania zmian. (W rzeczywistości, jeśli nadal masz tablicę A wspomnianą powyżej, możesz łatwo ją trochę rozszerzyć, aby rozwiązać ten problem: robimy ją tablicą A [ 1 … | T | , 1 … n ′ ] , nadal wypełniamy wszystkie dodatkowych wpisów i upewnij się, że A [ | T | , n + 1 ] , A [ | T | , n + 2 ] ,A A[1…|T|,1…n′] … , A [ | T | , n ′ ] są prawdziwe.) Teraz możemy wyliczyć wszystkie multisety T, które rozciągają S o jeden element i które spełniają oba warunki.A[|T|,n+1],A[|T|,n+2],…,A[|T|,n′] T S
To natychmiast sugeruje algorytm do wyliczenia wszystkich multisetów S, które spełniają twój warunek, dla wszystkich n do pewnego związanego, powiedzmy n ≤ 20 . Będziemy mieli tablicę P [ 1 … 20 ] , w której P [ 5 ] przechowuje wszystkie multisety S, które sumują się do 5, i ogólnie P [ n ] przechowuje zbiór wszystkich multisetów S, które sumują się do n .S n n≤20 P[1…20] P[5] S P[n]
Następnie możemy iteracyjnie wypełnić P [ n ] . Zacznij od ustawienia P [ 1 ] tak, aby zawierał tylko jeden multiset { 1 } . Następnie, dla każdego n (liczy się od 1 do 20), dla każdego S ∈ p [ n ] , wyliczyć wszystkich możliwych rozszerzeń T z S (z wykorzystaniem technik wyżej), niech n " oznacza sumę elementów T , i wstawić T do P [ n ′ ]jeśli nie jest już obecny, a jeśli n ' ≤ 20 .
To powinno być całkiem wykonalne. Powodzenia! Baw się dobrze! Przepracowanie szczegółów będzie dobrym ćwiczeniem do nauki w programowaniu dynamicznym.
źródło