Masalahku. Diberikan n
- Jumlah elemen S
S adalah nn , dan - Setiap nomor dari 1
1 ke nn dapat dinyatakan unik sebagai jumlah dari beberapa elemen SS .
Contoh.
Sebagai contoh jika n = 5
Namun, S = { 1 , 1 , 1 , 2 }
S = { 1 , 2 , 4
Saya sudah mencoba menemukan algoritma yang baik untuk masalah ini untuk beberapa waktu tetapi tidak dapat menyelesaikannya. Itu dari codechef . Saya telah melihat beberapa solusi yang diajukan tetapi saya masih tidak bisa mendapatkan logika untuk menyelesaikan masalah. CATATAN: Batas waktu untuk pertanyaan adalah 10 detik dan n < 10 9
Untuk multiset saya akan menggunakan notasi S = { ( a 1 , c 1 ) , ( a 2 , c 2 ) . . . }
Sampai sekarang saya telah menarik beberapa kesimpulan
- Elemen pertama dari multiset yang diurutkan haruslah 1
1 - Misalkan S = { 1 , a 2 ⋯ a k } | a 1 ≤ a 2 ⋯ ≤ a k menjadi set berikut dua sifat kemudian ∀ r < k a r + 1 = a r atau ( Σ r i = 0 a i ) + 1
S={1,a2⋯ak}|a1≤a2⋯≤ak ∀r<k ar+1=ar or (∑ri=0ai)+1 - Misalkan S = { ( 1 , c 1 ) , ( a 2 , c 2 ) ⋯ ( a k , c k ) } | a 1 ≤ a 2 ⋯ ≤ a k , di mana a i terjadi c i kali, mengikuti properti yang diperlukan kemudian dari kesimpulan di atas kita dapat mengatakan bahwa ∀ i a i | n + 1 dan
S={(1,c1),(a2,c2)⋯(ak,ck)}|a1≤a2⋯≤ak ai ci ∀i ai|n+1 a i | a j if j > i . Bukti: a i + 1 = ( a i c i + a i - 1 ) + 1 ⇒ a i | a i + 1ai|aj j>i ai+1=(aici+ai−1)+1⇒ai|ai+1 - Sekarang perhatikan S = { 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 , ⋯ } yaitu semua angka selanjutnya setelah 1 akan menjadi kelipatan d . Jadi, biarkan f ( n )
S={1,1⋯1d−1,d,d⋯d,dm1,dm1⋯dm1,dm2,dm2⋯dm2,⋯} d f(n) mungkin hitungan multiset seperti itu maka f ( n ) = β d | n + 1 , d ≠ 1 f ( n - ( d - 1 )d ) dimana saya menjumlahkan semua kemungkinan jumlah1′s(=d-1). Dengan kata lainf(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)
Akhirnya masalah saya berkurang menjadi ini - temukan g ( n ) dengan cara yang efisien sehingga tidak melebihi batas waktu.
sumber
Jawaban:
Inilah solusi tercepat yang dilakukan. Ini memang menghitung fungsi Anda g ( n ) = ∑ d ∣ n d < n g ( d ) ,g ( 1 ) = 1. Diberikan n , kita memfaktorkannya (lihat di bawah) dan kemudian menghitung semua faktor (lihat di bawah) f 1 , … , f m dalam beberapa urutan sedemikian rupa sehingga f i | f j menyiratkan saya ≤ j (properti P). Kami sekarang menghitung g sesuai dengan rumus dengan memeriksa faktor-faktor dalam urutan yang diberikan. Memastikan properti P bahwa ketika kita menghitung g ( d ) , kita sudah dihitung g ( e ) untuk semua non-sepele faktor e
Secara lebih rinci, kita membahas faktor-faktor secara berurutan, dan untuk setiap faktor f i , kita menemukan semua faktor non-sepele dengan memeriksa mana dari f 1 , … , f i - 1 yang membagi f i .fi f1,…,fi−1 fi
Anjak: Pra proses: kami membuat daftar semua bilangan prima di bawah 10 9 menggunakan saringan Eratosthenes. Diberikan n , kami hanya menggunakan divisi percobaan.109 n
Menghasilkan semua faktor: Ini dilakukan secara rekursif. Misalkan n = p k 1 1 ⋯ p k t t . Kami menjalankan t bersarang loop l 1 ∈ { 0 , ... , k 1 } , ... , l t ∈ { 0 , ... , k t } , dan output p l 1 1 ⋯ p l t t . Anda dapat membuktikan properti P dengan induksi.n=pk11⋯pktt t l1∈{0,…,k1},…,lt∈{0,…,kt} pl11⋯pltt
Optimasi: Karena program dijalankan pada beberapa input, kita dapat menggunakan memoisasi untuk menghemat waktu di berbagai input. Kami hanya memoize nilai kecil (hingga 10 5 ), dan ini memungkinkan kami untuk menyimpan semua nilai memoised dalam array. Array diinisialisasi dengan nol, sehingga kami dapat mengetahui nilai mana yang sudah diketahui (karena semua nilai yang dikomputasi adalah positif).105
Jika faktorisasi prima dari n + 1 adalah p k 1 1 , ... , p k t t , maka f ( n ) hanya bergantung pada ( k 1 , ... , k t ) , dan pada kenyataannya hanya pada versi diurutkan dari vektor ini . Setiap angka di bawah 10 9 memiliki paling banyak 29 faktor prima (dengan pengulangan), dan karena p ( 29 ) = 4565 , tampaknya layak untuk menghitung fn+1 pk11,…,pktt f(n) (k1,…,kt) 109 29 p(29)=4565 f (atau lebih tepatnya g ) untuk semuanya, secara rekursif. Solusi ini bisa lebih cepat jika ada banyak input yang berbeda; seperti itu, ada paling banyak 10 .g 10
Mungkin juga bahwa fungsi ini, memetakan partisi ke g terkait , memiliki bentuk analitik yang eksplisit. Misalnya, g ( p k ) = 2 k - 1 , g ( p 1 ... p t ) diberikan oleh A000670 , dan g ( p 2 1 p 2 ... p t ) diberikan oleh A005649 atau A172109 .g g(pk)=2k−1 g(p1…pt) g(p21p2…pt)
sumber
Oke, jadi Anda memiliki relasi perulangan untuk g ( ⋅ ) (lihat akhir pertanyaan Anda).g(⋅)
Pada titik ini sepertinya pendekatan alami adalah menuliskan algoritma rekursif untuk menghitung g ( n ) , dan menerapkan memoisasi sehingga Anda tidak menghitung g ( i ) lebih dari sekali. Dengan kata lain, ketika Anda menghitung g ( i ) , Anda menyimpannya dalam tabel hash yang memetakan i ↦ g ( i ) ; jika Anda perlu tahu g ( i ) lagi di masa depan, Anda bisa mencarinya di tabel hash.g(n) g(i) g(i) i↦g(i) g(i)
Ini memang membutuhkan anjak n , tetapi ada algoritma yang efisien untuk anjak n saat n ≤ 10 9 .n n n≤109
Anda mungkin juga mencari urutan g ( 1 ) , g ( 2 ) , g ( 3 ) , g ( 4 ) , g ( 5 ) , ... di Ensiklopedia On-Line dari Urutan Integer . Jika Anda menemukan urutan dalam ensiklopedia mereka, kadang-kadang mereka akan memberikan informasi bermanfaat tambahan (misalnya, algoritma yang efisien untuk menghitung urutan). Meskipun demikian, hal itu memang bisa menyenangkan.g(1),g(2),g(3),g(4),g(5),…
sumber
Inilah petunjuk untuk memulai. Menerapkan algoritma pemrograman dinamis standar untuk menghitung sekumpulan partisi integer, dan menambahkan beberapa logika untuk memeriksa yang mana dari yang memungkinkan untuk membuat perubahan unik dengan mengecek semua jumlah, membuat perubahan , dan memverifikasi keunikan secara iteratif .
Dalam sedikit lebih rinci: Misalkan Anda memiliki multiset S . Diberi nomor i dengan 1 ≤ i ≤ n , bagaimana Anda bisa mengidentifikasi submultiset S yang berjumlah i ? Bagaimana Anda bisa mengecek apakah submultiset itu unik? Cobalah untuk mengadaptasi teknik pemrograman dinamis standar untuk membuat perubahan . (Lihat juga pertanyaan ini .)S i 1≤i≤n S i
Diberikan multiset S , bagaimana Anda bisa mengecek apakah memenuhi kondisi kedua, yaitu, apakah setiap angka dari 1 hingga n dapat dinyatakan secara unik sebagai jumlah dari sebuah sub-sub S (kondisi perubahan-pembuatan yang unik)? Ini seharusnya cukup mudah, jika Anda memecahkan yang sebelumnya.S n S
misalkan P ( n ) menunjukkan daftar multiset yang memenuhi kedua kondisi Anda. Jika Anda tahu P ( 1 ) , P ( 2 ) , ... , P ( n ) , bagaimana Anda bisa menggunakan informasi itu untuk membangun P ( n + 1 ) ? Di sini Anda mungkin ingin mengadaptasi teknik pemrograman dinamis standar untuk enumerasi partisi integer.P(n) P(1),P(2),…,P(n) P(n+1)
Inilah pendekatan yang mungkin akan lebih baik.
Misalkan S adalah multiset yang memenuhi kedua kondisi Anda (untuk n ). Bagaimana kita bisa memperluasnya untuk mendapatkan T multiset yang memiliki satu elemen lebih? Dengan kata lain, bagaimana kita bisa mengidentifikasi semua cara untuk menambahkan satu elemen lagi ke S , untuk mendapatkan multiset T baru yang memenuhi kedua kondisi Anda (untuk beberapa n ′ )?S n T S T n′
Jawaban: jika x dapat dinyatakan sebagai jumlah dari beberapa elemen S , maka tidak ada gunanya menambahkannya ke S : itu akan menyebabkan T melanggar kondisi keunikan. Jadi, kita dapat menghitung semua bilangan bulat x yang tidak dapat dinyatakan sebagai jumlah dari beberapa elemen S ; masing-masing adalah sesuatu yang berpotensi ditambahkan ke S untuk mendapatkan multiset T baru yang akan memenuhi kedua kondisi (untuk beberapa n lainnya ).x S S T x S S T n
Selain itu, dimungkinkan untuk menyebutkan bilangan bulat mana yang dapat dinyatakan sebagai jumlah dari beberapa elemen S , dan yang tidak bisa, menggunakan pemrograman dinamis. Anda membangun array dua dimensi A [ 1 … | S | , 1 ... n ] dari boolean, di mana A [ i , j ] benar jika ada cara untuk mengekspresikan integer j sebagai jumlah dari beberapa elemen i pertama S (hanya elemen i pertama S yang memenuhi syarat untuk digunakan, di mana SS A[1…|S|,1…n] A[i,j] j i S i S S telah disortir, jadi S = { s 1 , s 2 , … , s k } dan s 1 ≤ s 2 ≤ ⋯ ≤ s k ). Perhatikan bahwa A [ i , j ] dapat dihitung menggunakan nilai-nilai A [ 1 ... i - 1 , 1 ... j - 1 ] : khususnya, 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 ] jika j > s i , atau A [ i , j ] = A [ i - 1 , j ] jika tidak. Hal ini memungkinkan kita untuk mengidentifikasi semua nomor yang calon yang akan ditambahkan ke S .A[i,j]=A[i−1,j]∨A[i−1,j−si] j>si A[i,j]=A[i−1,j] S
Selanjutnya, untuk setiap kandidat ekstensi T dari S (diperoleh dengan menambahkan satu elemen ke S ), kami ingin memeriksa apakah T memenuhi kedua kondisi. Biarkan n menunjukkan jumlah dari unsur S , dan n ' jumlah dari unsur-unsur T . Kita perlu memeriksa apakah setiap bilangan bulat dalam kisaran n + 1 , n + 2 , ... , n ′ dapat dinyatakan sebagai jumlah dari beberapa elemen TT S S T n S n′ T n+1,n+2,…,n′ T . Ini juga dapat diselesaikan dengan menggunakan pemrograman dinamis, menggunakan algoritma standar untuk membuat perubahan. (Faktanya, jika Anda masih memiliki array A yang disebutkan di atas, Anda dapat dengan mudah memperluasnya sedikit untuk menyelesaikan masalah ini: kami menjadikannya array A [ 1 ... | T | , 1 ... n ′ ] , terus isi semua dari entri tambahan, dan pastikan bahwa A [ | T | , n + 1 ] , A [ | T | , n + 2 ] ,A A[1…|T|,1…n′] … , A [ | T | , n ′ ] semuanya benar.) Jadi, sekarang kita dapat menghitung semua multiset T yang memperpanjang S dengan satu elemen dan yang memenuhi kedua kondisi tersebut.A[|T|,n+1],A[|T|,n+2],…,A[|T|,n′] T S
Ini segera menyarankan suatu algoritma untuk menghitung semua multiset S yang memenuhi kondisi Anda, untuk semua n hingga beberapa batasan, katakanlah n ≤ 20 . Kita akan memiliki array P [ 1 ... 20 ] , di mana P [ 5 ] menyimpan semua multiset S yang berjumlah 5, dan secara umum, P [ n ] menyimpan set semua semua multiset S yang menjumlahkan n .S n n≤20 P[1…20] P[5] S P[n] S n
Selanjutnya, kita dapat mengisi P [ n ] secara iteratif. Mulailah dengan mengatur P [ 1 ] untuk memuat hanya satu multiset { 1 } . Berikutnya, untuk setiap n (menghitung dari 1 hingga 20), untuk setiap S ∈ P [ n ] , menyebutkan semua kemungkinan ekstensi T dari S (menggunakan teknik di atas), misalkan n ′ menunjukkan jumlah elemen T , dan masukkan T ke P [ n ′ ]P[n] P[1] {1} n S∈P[n] T S n′ T T P[n′] jika belum ada dan jika n ′ ≤ 20 .n′≤20
Ini harusnya bisa dilakukan. Semoga berhasil! Selamat bersenang-senang! Bekerja melalui detail akan menjadi latihan pembelajaran yang baik dalam pemrograman dinamis.
sumber