Katakanlah kita memiliki bilangan bulat non-negatif yang "kekar" (yaitu, "berat") jika nilai digit rata-rata lebih besar dari 7.
Angka 6959 adalah "kekar" karena:
(6 + 9 + 5 + 9) / 4 = 7.5
Angka 1234 tidak, karena:
(1 + 2 + 3 + 4) / 4 = 2.5
Tulis fungsi, dalam bahasa apa pun,
HeftyDecimalCount(a, b)
yang, ketika memberikan dua bilangan bulat positif a dan b mengembalikan bilangan bulat yang menunjukkan berapa banyak bilangan bulat "kekar" dalam interval [a..b], inklusif.
Misalnya, diberi a = 9480 dan b = 9489:
9480 (9+4+8+0)/4 21/4 = 5.25
9481 (9+4+8+1)/4 22/4 = 5.5
9482 (9+4+8+2)/4 23/4 = 5.75
9483 (9+4+8+3)/4 24/4 = 6
9484 (9+4+8+4)/4 25/4 = 6.25
9485 (9+4+8+5)/4 26/4 = 6.5
9486 (9+4+8+6)/4 27/4 = 6.75
9487 (9+4+8+7)/4 28/4 = 7
9488 (9+4+8+8)/4 29/4 = 7.25 hefty
9489 (9+4+8+9)/4 30/4 = 7.5 hefty
Dua angka dalam rentang ini adalah "kekar" dan karenanya fungsi harus mengembalikan 2.
Beberapa pedoman:
- berasumsi bahwa a atau b tidak melebihi 200.000.000.
- solusi n-squared akan bekerja, tetapi akan lambat - apa yang tercepat yang bisa kita selesaikan ini?
Jawaban:
Masalahnya dapat diselesaikan di O (polylog (b)).
Kami mendefinisikan
f(d, n)
jumlah bilangan bulat hingga d angka desimal dengan jumlah digit kurang dari atau sama dengan n. Dapat dilihat bahwa fungsi ini diberikan oleh rumusDengan menggunakan rumus ini, misalnya kita dapat menemukan jumlah angka berat dalam interval dari 8000 hingga 8999 sebagai
1000 - f(3, 20)
, karena ada ribuan angka dalam interval ini, dan kita harus mengurangi jumlah angka dengan jumlah digit kurang dari atau sama dengan 28 sambil memperhitungkan bahwa digit pertama sudah memberikan kontribusi 8 ke jumlah digit.Sebagai contoh yang lebih kompleks mari kita lihat jumlah angka berat dalam interval 1234..5678. Pertama-tama kita dapat beralih dari 1234 ke 1240 dalam langkah-langkah 1. Kemudian kita beralih dari 1240 hingga 1300 dalam langkah-langkah 10. Rumus di atas memberi kita jumlah angka berat dalam setiap interval seperti itu:
Sekarang kita beralih dari 1300 ke 2000 dalam langkah 100:
Dari 2000 hingga 5000 dalam langkah 1000:
Sekarang kita harus mengurangi ukuran langkah lagi, dari 5000 menjadi 5600 di langkah 100, dari 5600 ke 5670 di langkah 10 dan akhirnya dari 5670 menjadi 5678 di langkah 1.
Contoh implementasi Python (yang menerima sedikit optimisasi dan pengujian sementara itu):
Sunting : Mengganti kode dengan versi yang dioptimalkan (yang terlihat lebih jelek dari kode aslinya). Juga memperbaiki beberapa kasus sudut saat saya berada di sana.
heavy(1234, 100000000)
membutuhkan waktu sekitar satu milidetik pada mesin saya.sumber
binomial()
fungsi. Ada juga beberapa hal lagi yang dapat dengan mudah ditingkatkan. Saya akan memposting pembaruan dalam beberapa menit.f(d, n)
tidak dipanggil dua kali dengan parameter yang sama selama satu kali menjalankan program.Perulangan, dan gunakan permutasi.
Misalkan kita mendefinisikan fungsi umum yang menemukan nilai antara a dan b dengan bobot lebih dari x:
Dengan contoh Anda dari a = 8675 ke b = 8689, angka pertama adalah 8, jadi buanglah - jawabannya akan sama dengan 675 hingga 689, dan lagi dari 75 menjadi 89.
Berat rata-rata dari dua digit pertama 86 adalah 7, sehingga digit yang tersisa membutuhkan berat rata-rata lebih dari 7 untuk memenuhi syarat. Demikian panggilan
setara dengan
Jadi rentang kami untuk digit pertama (baru) adalah 7 hingga 8, dengan kemungkinan ini:
Untuk 7, kita masih membutuhkan rata-rata lebih dari 7, yang hanya bisa berasal dari angka akhir 8 atau 9, memberi kita 2 nilai yang mungkin.
Untuk 8, kita membutuhkan rata-rata lebih dari 6, yang hanya bisa berasal dari digit akhir 7-9, memberi kita 3 nilai yang mungkin.
Jadi, 2 + 3 menghasilkan 5 nilai yang mungkin.
Apa yang terjadi adalah bahwa algoritma tersebut dimulai dengan angka 4 digit dan membaginya menjadi masalah yang lebih kecil. Fungsi ini akan menyebut dirinya berulang kali dengan versi masalah yang lebih mudah sampai memiliki sesuatu yang dapat ditangani.
sumber
Mungkin Anda dapat melewati banyak kandidat dalam interval dari a ke b dengan mengumpulkan "berat" mereka.
jika Anda tahu panjang angka Anda, Anda tahu bahwa setiap digit dapat mengubah berat hanya 1 / panjang.
Jadi, jika Anda mulai dari satu angka yang tidak berat Anda harus dapat menghitung angka berikutnya yang akan berat, jika Anda menambahnya dengan satu.
Dalam contoh Anda di atas mulai dari 8680 rata-rata = 5,5, yang 7-5,5 = 1,5 poin dari Anda batas berat, Anda akan tahu bahwa ada 1,5 / (1/4) = 6 angka di antaranya, yang TIDAK berat.
Itu seharusnya untuk trik!
sumber
/length
itu.Bagaimana dengan fungsi rekursif sederhana? Untuk menjaga hal-hal sederhana, ini menghitung semua angka berat dengan
digits
digit, dan jumlah digit minimalmin_sum
.Diimplementasikan ini dalam python dan menemukan semua angka berat 9 digit dalam ~ 2 detik. Sedikit pemrograman dinamis dapat meningkatkan ini.
sumber
Ini adalah salah satu solusi yang mungkin.
sumber
C, untuk interval [a, b] itu adalah O (ba)
//Latihan
//hasil
sumber