Jumlah multiset sehingga setiap angka dari 1 hingga

11

Masalahku. Diberikan nn , saya ingin menghitung jumlah multiset S yang valid S. Sebuah multiset SS valid jika

  • Jumlah elemen SS adalah nn , dan
  • Setiap nomor dari 11 ke nn dapat dinyatakan unik sebagai jumlah dari beberapa elemen SS .

Contoh. Sebagai contoh jika n = 5n=5 maka { 1 , 1 , 1 , 1 , 1 } , { 1 , 2 , 2 } , { 1 , 1 , 3 }{1,1,1,1,1},{1,2,2},{1,1,3} valid.

Namun, S = { 1 , 1 , 1 , 2 }S={1,1,1,2} tidak valid karena 2 dapat dibentuk oleh { 1 , 1 }{1,1} dan { 2 }{2} (yaitu, 2 dapat dinyatakan sebagai 2 = 1 + 12=1+1 dan 2 = 22=2 ) , jadi kondisi kedua tidak berlaku. Demikian pula 3 dapat dibentuk oleh { 2 , 1 }{2,1} dan { 1 , 1 , 1 }{1,1,1} .

S = { 1 , 2 , 4S={1,2,4 } juga tidak valid karena semua angka dari 11 hingga 55 dapat dibuat secara unik, tetapi jumlah elemen SS bukan 55 .


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 9n<109

Untuk multiset saya akan menggunakan notasi S = { ( a 1 , c 1 ) , ( a 2 , c 2 ) . . . } S={(a1,c1),(a2,c2)...} a i < a jai<aj if i < ji<j , yang berarti a sayaai muncul c ici kali dalam multiset S.

Sampai sekarang saya telah menarik beberapa kesimpulan

  • Elemen pertama dari multiset yang diurutkan haruslah 11
  • Misalkan S = { 1 , a 2a k } | a 1a 2a k menjadi set berikut dua sifat kemudian r < k a r + 1 = a r  atau  ( Σ r i = 0 a i ) + 1S={1,a2ak}|a1a2ak  r<k  ar+1=ar or (ri=0ai)+1
  • Misalkan S = { ( 1 , c 1 ) , ( a 2 , c 2 ) ( a k , c k ) } | a 1a 2a 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 danS={(1,c1),(a2,c2)(ak,ck)}|a1a2akaici i ai|n+1a i | a j if j > i . Bukti: a i + 1 = ( a i c i + a i - 1 ) + 1 a i | a i + 1ai|ajj>i
    ai+1=(aici+ai1)+1ai|ai+1
  • Sekarang perhatikan S = { 1 , 1 1 d - 1 , d , d d , d m 1 , d m 1d m 1 , d m 2 , d m 2d m 2 , } yaitu semua angka selanjutnya setelah 1 akan menjadi kelipatan d . Jadi, biarkan f ( n )S={1,11d1,d,dd,dm1,dm1dm1,dm2,dm2dm2,}df(n)mungkin hitungan multiset seperti itu maka f ( n ) = β d | n + 1 , d 1 f ( n - ( d - 1 )d ) dimana saya menjumlahkan semua kemungkinan jumlah1s(=d-1). Dengan kata lainf(n-1)=g(n)=βd| n,dng(d)f(n)=d|n+1,d1f(n(d1)d)1s=d1f(n1)=g(n)=d|n,dng(d)

Akhirnya masalah saya berkurang menjadi ini - temukan g ( n ) dengan cara yang efisien sehingga tidak melebihi batas waktu.g(n)

Liga keadilan
sumber
2
Sudahkah Anda memeriksa apakah pantas untuk meminta orang lain memposting solusi dan algoritma untuk masalah praktik secara publik? FAQ Codechef tampaknya mengharapkan bahwa solusi tidak akan diposting secara publik (kecuali untuk beberapa masalah yang sangat mendasar). Apakah memposting solusi di sini akan "merusak" masalah latihan untuk orang lain, atau apakah itu dianggap OK? Saya tidak terbiasa dengan norma dan etiket komunitas Codechef.
DW
Saya tidak menemukan apa pun yang terkait dengan tidak mengirimkan pertanyaan pada domain publik dalam faq dan pembatasan ini ada pada masalah kontes yang sedang berlangsung, bukan pada masalah praktik.
liga keadilan
1
@DW Saya tidak berpikir mereka akan keberatan jika kita membahas masalah yang bukan dari kontes yang sedang berlangsung.
Ravi Upadhyay
1
Anda mencari jumlah partisi dari jumlah input. Saya sarankan Anda melakukan riset menggunakan kata kunci ini.
Raphael
2
@ Raphael, saya setuju, poster itu harus membaca tentang teknik-teknik itu. Ini bukan masalah yang persis sama - kondisi pertama poster mengharuskan ini menjadi partisi, tetapi kondisi kedua memaksakan pembatasan tambahan (untuk pembuatan perubahan unik ) - tetapi dimungkinkan untuk menerapkan teknik yang sama yang digunakan untuk menghitung nomor partisi, dengan beberapa modifikasi untuk menangani persyaratan tambahan.
DW

Jawaban:

2

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

g(n)=dnd<ng(d),g(1)=1.
nf1,,fmfi|fjijgg(d)g(e)edari d . Ada juga optimasi (lihat di bawah).d

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 .fif1,,fi1fi

Anjak: Pra proses: kami membuat daftar semua bilangan prima di bawah 10 9 menggunakan saringan Eratosthenes. Diberikan n , kami hanya menggunakan divisi percobaan.109n

Menghasilkan semua faktor: Ini dilakukan secara rekursif. Misalkan n = p k 1 1p k t t . Kami menjalankan t bersarang loop l 1{ 0 , ... , k 1 } , ... , l t{ 0 , ... , k t } , dan output p l 1 1p l t t . Anda dapat membuktikan properti P dengan induksi.n=pk11pktttl1{0,,k1},,lt{0,,kt}pl11pltt

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+1pk11,,pkttf(n)(k1,,kt)10929p(29)=4565f(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 .g10

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 .gg(pk)=2k1g(p1pt)g(p21p2pt)

Yuval Filmus
sumber
1

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)ig(i)g(i)

Ini memang membutuhkan anjak n , tetapi ada algoritma yang efisien untuk anjak n saat n 10 9 .nnn109

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),

DW
sumber
0

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 .)Si1inSi

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.SnS

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 )?SnTSTn

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 ).xSSTxSSTn

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 SSA[1|S|,1n]A[i,j]jiSiSStelah disortir, jadi S = { s 1 , s 2 , , s k } dan s 1s 2s 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}s1s2skA[i,j]A[1i1,1j1]= 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[i1,j]A[i1,jsi]j>siA[i,j]=A[i1,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 TTSSTnSnTn+1,n+2,,nT. 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 ] ,AA[1|T|,1n], 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]TS

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 .Snn20P[120]P[5]SP[n]Sn

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}nSP[n]TSnTTP[n]jika belum ada dan jika n 20 .n20

Ini harusnya bisa dilakukan. Semoga berhasil! Selamat bersenang-senang! Bekerja melalui detail akan menjadi latihan pembelajaran yang baik dalam pemrograman dinamis.

DW
sumber
Saya tidak dapat menghitung semua partisi integer karena itu akan eksponensial. Saya telah mengedit pertanyaan dan memasukkan kisaran n dan beberapa pemikiran saya, tetapi masih saja saya mandek. Mungkin Anda bisa membantu.
liga keadilan