Bilangan bulat yang diberikan n
, hitung satu set n
bilangan bulat unik acak dalam rentang 1..n^2
(inklusif) sehingga jumlah himpunan sama dengann^2
Acak, dalam hal ini, berarti acak seragam antara keluaran yang valid. Setiap output yang valid untuk suatu yang diberikan n
harus memiliki peluang seragam untuk dihasilkan.
Misalnya, n=3
harus memiliki kesempatan 1/3 masing-masing keluaran 6, 1, 2
, 3, 5, 1
atau 4, 3, 2
. Karena ini adalah himpunan, urutan tidak relevan, 4, 3, 2
identik dengan3, 2, 4
Mencetak gol
Pemenangnya adalah program yang dapat menghitung tertinggi n
dalam waktu kurang dari 60 detik.
Catatan: Untuk mencegah kemungkinan hardcoding parsial, semua entri harus kurang dari 4000 byte
Pengujian
Semua kode akan dijalankan pada mesin Windows 10 lokal saya (Razer Blade 15, RAM 16GB, Intel i7-8750H 6 core, 4.1GHz, GTX 1060 jika Anda ingin menyalahgunakan GPU) jadi harap berikan instruksi terperinci untuk menjalankan kode Anda di mesin saya.
Atas permintaan, entri dapat dijalankan melalui Debian di WSL, atau di Mesin Virtual Xubuntu (keduanya di mesin yang sama seperti di atas)
Pengajuan akan dijalankan 50 kali berturut-turut, skor akhir akan menjadi rata-rata dari semua 50 hasil.
sumber
Jawaban:
Karat , n ≈ 1400
Bagaimana cara menjalankannya
Bangun dengan
cargo build --release
, dan jalankan bersamatarget/release/arbitrary-randomness n
.Program ini berjalan tercepat dengan banyak memori (asalkan tidak bertukar, tentu saja). Anda dapat menyesuaikan penggunaan memorinya dengan mengedit
MAX_BYTES
konstanta, yang saat ini ditetapkan pada 8 GiB.Bagaimana itu bekerja
Himpunan dibangun oleh urutan keputusan biner (masing-masing angka baik di dalam atau di luar himpunan), masing-masing yang probabilitas dihitung secara kombinatorial dengan menghitung jumlah set yang mungkin dibangun setelah setiap pilihan menggunakan pemrograman dinamis.
Penggunaan memori untuk besar n dikurangi dengan menggunakan versi strategi partisi binomial ini .
Cargo.toml
src/main.rs
Cobalah online!
(Catatan: versi TIO memiliki beberapa modifikasi. Pertama, batas memori dikurangi menjadi 1 GiB. Kedua, karena TIO tidak membiarkan Anda menulis
Cargo.toml
dan bergantung pada peti eksternal sepertirand
, saya malah menarikdrand48
dari perpustakaan C menggunakan FFI. Saya tidak repot-repot me-seed-kannya, jadi versi TIO akan menghasilkan hasil yang sama setiap kali dijalankan. Jangan gunakan versi TIO untuk pembandingan resmi.)sumber
ln_add_exp
dengan memeriksa apakah perbedaan absolut lebih besar dari ~ 15 atau lebih, yang mungkin lebih cepat jika ada banyak penambahan semacam itu.ln_add_exp
panggilan melibatkan input yang sebanding.Java 7+, n = 50 dalam ~ 30 dtk di TIO
Versi jawaban saya yang tidak digabungkan untuk versi kode-golf dari tantangan ini untuk saat ini, dengan hanya satu perubahan kecil:
java.util.Random#nextInt(limit)
digunakan sebagai ganti(int)(Math.random()*limit)
untuk bilangan bulat dalam kisaran[0, n)
, karena ini sekitar dua kali lebih cepat .Cobalah online.
Penjelasan:
Pendekatan yang digunakan:
Kode ini dibagi menjadi dua bagian:
n
jumlah bilangan bulat acak yang dijumlahkann squared
.Langkah 1 dilakukan dengan sub-langkah berikut:
1) Hasilkan array
n-1
jumlah integer acak dalam rentang[0, n squared)
. Dan tambahkan0
dann squared
ke daftar ini. Ini dilakukan dalamO(n+1)
kinerja.2) Kemudian akan mengurutkan array dengan builtin
java.util.Arrays.sort(int[])
, ini dilakukan dalamO(n*log(n))
kinerja, seperti yang dinyatakan dalam dokumen:3) Hitung perbedaan antara masing-masing pasangan. Daftar perbedaan yang dihasilkan ini akan berisi
n
bilangan bulat yang dijumlahkann squared
. Ini dilakukan diO(n)
kinerja.Berikut sebuah contoh:
Jadi tiga langkah di atas cukup baik untuk kinerja, tidak seperti langkah 2 dan lingkaran di sekitar semuanya, yang merupakan kekuatan kasar dasar. Langkah 2 dibagi dalam sub-langkah ini:
1) Daftar perbedaan sudah disimpan dalam a
java.util.Set
. Ini akan memeriksa apakah ukuran Set ini sama dengann
. Jika ya, itu berarti semua nilai acak yang kami hasilkan adalah unik.2) Dan itu juga akan memeriksa bahwa itu tidak mengandung
0
dalam Set, karena tantangan meminta nilai acak dalam kisaran[1, X]
, di manaX
adalahn squared
dikurangi jumlah[1, ..., n-1]
, seperti yang dinyatakan oleh @Skidsdev dalam komentar di bawah ini.Jika salah satu dari dua opsi di atas (tidak semua nilai unik, atau nol ada), itu akan menghasilkan array baru dan Atur lagi dengan mengatur ulang ke langkah 1. Ini berlanjut sampai kita mendapatkan hasil. Karena itu, waktunya dapat sedikit berbeda. Saya telah melihatnya selesai dalam 3 detik sekali pada TIO untuk
n=50
, tetapi juga dalam 55 detik sekali untukn=50
.Buktikan keseragaman:
Saya tidak sepenuhnya yakin bagaimana membuktikan ini sepenuhnya jujur. Yang pasti
java.util.Random#nextInt
seragam, seperti yang dijelaskan dalam dokumen:Perbedaan antara nilai-nilai acak ini (diurutkan) sendiri tentu saja tidak seragam, tetapi set secara keseluruhan seragam. Sekali lagi, saya tidak yakin bagaimana membuktikan ini secara matematis, tetapi di sini ada skrip yang akan meletakkan
10,000
set yang dihasilkan (untukn=10
) di Peta dengan penghitung , di mana sebagian besar set unik; beberapa diulang dua kali; dan kejadian berulang maksimum biasanya dalam kisaran[4,8]
.Instruksi instalasi:
Karena Java adalah bahasa yang cukup terkenal dengan banyak informasi yang tersedia tentang cara membuat dan menjalankan kode Java, saya akan membuat ini singkat.
Semua alat yang digunakan dalam kode saya tersedia di Java 7 (mungkin bahkan sudah ada di Java 5 atau 6, tapi mari kita gunakan 7 untuk berjaga-jaga). Saya cukup yakin Java 7 sudah diarsipkan, jadi saya sarankan mengunduh Java 8 untuk menjalankan kode saya.
Pikiran tentang perbaikan:
Saya ingin mencari peningkatan untuk memeriksa nol dan memeriksa semua nilai unik. Saya dapat memeriksa
0
sebelumnya, dengan memastikan nilai acak yang kita tambahkan ke array belum ada di dalamnya, tetapi itu akan berarti beberapa hal: array harusArrayList
jadi kita dapat menggunakan metode builtin.contains
; loop sementara harus ditambahkan hingga kami menemukan nilai acak yang belum ada dalam Daftar. Karena memeriksa nol sekarang dilakukan.contains(0)
pada Set (yang hanya diperiksa sekali), kemungkinan besar lebih baik untuk memeriksanya pada saat itu, dibandingkan dengan menambahkan loop dengan.contains
pada Daftar, yang akan diperiksa setidaknyan
kali , tetapi kemungkinan besar lebih.Adapun pemeriksaan keunikan, kami hanya memiliki
n
jumlah bilangan bulat acak kami yang berjumlahn squared
setelah langkah 1 program, jadi hanya dengan demikian kami dapat memeriksa apakah semuanya unik atau tidak. Dimungkinkan untuk menyimpan Daftar yang dapat diurutkan alih-alih array, dan memeriksa perbedaan di antara keduanya, tetapi saya benar-benar ragu itu akan meningkatkan kinerja daripada hanya memasukkannya ke dalamSet
dan memeriksa apakah ukuran Set itun
satu kali.sumber
n^2 - sum(1..n-1)
misalnya untukn=5
nomor valid terbesar adalah5^2 - sum(1, 2, 3, 4) == 25 - 10 == 15
n
, bukan? Dalam hal ini, Anda dapat menambahkan0
ke set, dan kemudian memeriksa bahwa ukurannya (sekarang) lebih darin
. Ini hanya dapat terjadi jika perbedaannya bukan nol dan berbeda.HashSet.contains
dalam kebanyakan kasus dekatO(1)
, dan dalam kasus terburuk adaO(n)
di Java 7, danO(log n)
di Java 8+ (telah ditingkatkan setelah mereka mengganti rantai dengan deteksi tabrakan). Jika saya diizinkan mengembalikan Set dengan tambahan0
untuk cek, maka itu memang sedikit lebih baik untuk kinerja, tetapi jika saya harus menelepon keset.remove(0);
dalam if, saya cukup yakin kinerjanya agak sama.Mathematica n = 11
sumber