Teorema empat persegi Lagrange memberi tahu kita bilangan alami dapat direpresentasikan sebagai jumlah dari empat bilangan kuadrat. Tugas Anda adalah menulis program yang melakukan ini.
Input: Jumlah alami (di bawah 1 miliar)
Output: Empat angka yang kuadratnya berjumlah ke angka itu (urutan tidak masalah)
Catatan: Anda tidak perlu melakukan pencarian brute force! Detail di sini dan di sini . Jika ada fungsi yang meremehkan masalah ini (saya akan tentukan), itu tidak diizinkan. Fungsi utama otomatis dan root kuadrat diperbolehkan. Jika ada lebih dari satu representasi, semua orang akan baik-baik saja. Jika Anda memilih untuk melakukan kekerasan, itu harus berjalan dalam waktu yang wajar (3 menit)
input sampel
123456789
keluaran sampel (baik-baik saja)
10601 3328 2 0
10601 3328 2
Jawaban:
CJam, 50 byte
Jawaban ketiga (dan terakhir, saya berjanji). Pendekatan ini sangat didasarkan pada jawaban primo .
Cobalah online di juru bahasa CJam .
Pemakaian
Latar Belakang
Setelah melihat algoritma primo yang diperbarui, saya harus melihat bagaimana skor implementasi CJam:
Hanya 58 byte! Algoritma ini bekerja dalam waktu yang hampir konstan dan tidak menunjukkan banyak variasi untuk nilai yang berbeda
N
. Mari kita ubah itu ...Alih-alih memulai
floor(sqrt(N))
dan mengurangi, kita bisa mulai1
dan menambah. Ini menghemat 4 byte.Alih-alih menyatakan
N
sebagai4**a * b
, kita dapat menyatakannya sebagaip**(2a) * b
- di manap
faktor prima terkecilN
- untuk menyimpan 1 byte lebih.Modifikasi sebelumnya memungkinkan kita untuk sedikit mengubah implementasi (tanpa menyentuh algoritme itu sendiri): Alih-alih membaginya
N
denganp**(2a)
dan melipatgandakan solusinyap**a
, kita dapat langsung membatasi solusi yang mungkin menjadi kelipatanp**a
. Ini menghemat 2 byte lagi.Tidak membatasi integer pertama untuk
p**a
menyimpan banyak byte tambahan.Algoritma terakhir
Temukan
a
danb
sedemikian rupaN = p**(2a) * b
, di manab
bukan kelipatanp**2
danp
merupakan faktor prima terkecilN
.Setel
j = p**a
.Setel
k = floor(sqrt(N - j**2) / A) * A
.Setel
l = floor(sqrt(N - j**2 - k**2) / A) * A
.Setel
m = floor(sqrt(N - j**2 - k**2 - l**2) / A) * A
.Jika
N - j**2 - k**2 - l**2 - m**2 > 0
, aturj = j + 1
dan kembali ke langkah 3.Ini dapat diimplementasikan sebagai berikut:
Tolak ukur
Saya telah menjalankan semua 5 versi di atas semua bilangan bulat positif hingga 999.999.999 pada Intel Core i7-3770 saya, mengukur waktu eksekusi dan menghitung iterasi yang diperlukan untuk menemukan solusi.
Tabel berikut ini menunjukkan jumlah rata-rata iterasi dan waktu eksekusi untuk satu integer:
Dengan hanya 4 iterasi dan 6,6 mikro per integer, algoritma primo sangat cepat.
Mulai dengan
floor(sqrt(N))
lebih masuk akal, karena ini memberi kita nilai yang lebih kecil untuk jumlah dari tiga kuadrat yang tersisa. Seperti yang diharapkan, mulai dari 1 jauh lebih lambat.Ini adalah contoh klasik dari ide bagus yang diterapkan dengan buruk. Untuk benar-benar mengurangi ukuran kode, kami bergantung pada
mF
, yang memengaruhi integerN
. Meskipun versi 3 membutuhkan iterasi yang lebih sedikit daripada versi 2, ini jauh lebih lambat dalam praktiknya.Meskipun algoritme tidak berubah, versi 4 jauh lebih lambat. Ini karena ia melakukan pembagian titik apung tambahan dan perkalian bilangan bulat di setiap iterasi.
Untuk input
N = p**(2a) ** b
, algoritma 5 akan membutuhkan(k - 1) * p**a + 1
iterasi, di manak
jumlah algoritma iterasi 4 membutuhkan. Jikak = 1
ataua = 0
, ini tidak ada bedanya.Namun, setiap input formulir
4**a * (4**c * (8 * d + 7) + 1)
mungkin berkinerja sangat buruk. Untuk nilai mulaij = p**a
,N - 4**a = 4**(a + c) * (8 * d + 7)
, sehingga tidak dapat dinyatakan sebagai jumlah dari tiga kotak. Jadi,k > 1
dan setidaknyap**a
diperlukan iterasi.Untungnya, algoritma asli primo sangat cepat dan
N < 1,000,000,000
. Kasus terburuk yang bisa saya temukan dengan tangan adalah265,289,728 = 4**10 * (4**1 * (7 * 8 + 7) + 1)
, yang membutuhkan 6.145 iterasi. Waktu eksekusi kurang dari 300 ms pada mesin saya. Rata-rata, versi ini 13,5 kali lebih lambat daripada penerapan algoritma primo.sumber
N
sebagai4**a * b
, kita dapat mengekspresikannya sebagaip**(2a) * b
." Ini sebenarnya perbaikan . Saya ingin memasukkan ini, tapi itu jauh lebih lama (yang ideal adalah menemukan faktor kuadrat sempurna terbesar). "Dimulai dengan 1 dan incrementing menghemat 4 byte." Ini pasti lebih lambat. Runtime untuk rentang tertentu adalah 4-5 kali lebih lama. "Semua bilangan bulat positif hingga 999.999.999 membutuhkan waktu 24,67 jam, memberikan waktu eksekusi rata-rata 0,0888 milidetik per bilangan bulat." Perl hanya butuh 2,5 jam untuk menyelesaikan seluruh jajaran, dan terjemahan Python 10x lebih cepat;)p**a
merupakan perbaikan, tapi itu kecil. Membagi dengan faktor kuadrat sempurna terbesar membuat perbedaan besar ketika mulai dari 1; ini masih merupakan peningkatan ketika mulai dari bagian integer dari akar kuadrat. Menerapkannya hanya akan memakan biaya dua byte lagi. Waktu eksekusi yang sangat buruk tampaknya disebabkan oleh ketidaksempurnaan saya, bukan CJam. Saya akan menjalankan kembali tes untuk semua algoritma (termasuk yang Anda usulkan), menghitung iterasi daripada mengukur waktu dinding. Mari kita lihat berapa lama yang dibutuhkan ...1\
bertukar dengan 1 (akumulator),mF
tekan faktorisasi dan{~2/#*}/
naikkan setiap faktor prima ke eksponennya dibagi dua, lalu gandakan dengan akumulator. Untuk implementasi langsung dari algoritma Anda, itu hanya menambahkan 2 byte. Perbedaan kecil terutama karena cara canggung saya harus menemukan eksponen 4, karena CJam tidak (tampaknya) memiliki loop sementara ...FRACTRAN:
15698 fraksiKarena ini adalah masalah teori bilangan klasik, cara apa yang lebih baik untuk menyelesaikan ini daripada menggunakan angka!
Mengambil input dari form 2 n × 193 dan output 3 a × 5 b × 7 c × 11 d . Dapat berjalan dalam 3 menit jika Anda memiliki juru bahasa yang sangat bagus. Mungkin.
Petunjuk
Kode ini setara dengan pseudo-Python berikut:
sumber
Mathematica
61 6651Tiga metode ditampilkan. Hanya pendekatan pertama yang memenuhi persyaratan waktu.
1-FindInstance (51 char)
Ini mengembalikan solusi tunggal persamaan.
Contoh dan timing
2-IntegerPartitions
Ini juga berfungsi, tetapi terlalu lambat untuk memenuhi persyaratan kecepatan.
Range[0, Floor@Sqrt@n]^2
adalah himpunan semua kuadrat kurang dari akar kuadrat (kuadratn
terbesar yang mungkin ada dalam partisi).{4}
membutuhkan partisi integern
terdiri dari 4 elemen dari set kuadrat yang disebutkan di atas.1
, dalam fungsiIntegerPartitions
mengembalikan solusi pertama.[[1]]
menghilangkan kawat gigi luar; solusi dikembalikan sebagai satu set elemen.3-PowerRepresentations
PowerRepresentations mengembalikan semua solusi ke masalah 4 kotak. Itu juga dapat memecahkan sejumlah kekuatan lain.
Representasi Powers kembali, dalam waktu kurang dari 5 detik, 181 cara untuk mengekspresikan 123456789 sebagai jumlah dari 4 kotak:
Namun, ini terlalu lambat untuk jumlah lainnya.
sumber
IntegerPartitions
. Seperti yang dapat Anda lihat dari timing, kecepatan bervariasi tergantung pada apakah nomor (terbesar) pertama dekat dengan akar kuadrat darin
. Terima kasih telah menangkap pelanggaran spesifikasi di versi sebelumnya.f[805306368]
? Tanpa membagi dengan kekuatan 4 pertama, solusi saya membutuhkan 0,05 untuk 999999999; Saya telah membatalkan patokan untuk 805306368 setelah 5 menit ...f[805306368]
kembali{16384, 16384, 16384}
setelah 21 menit. Saya menggunakan {3} sebagai pengganti {4}. Upaya untuk menyelesaikannya dengan jumlah 4 kotak non-nol tidak berhasil setelah beberapa jam berjalan.IntegerPartitions[n,4,Range[Floor@Sqrt@n]^2
harus bekerja juga. Namun, saya tidak berpikir Anda harus menggunakan metode 1 untuk skor Anda, karena tidak sesuai dengan batas waktu yang ditentukan dalam pertanyaan.Perl -
116 byte87 byte (lihat pembaruan di bawah)Menghitung shebang sebagai satu byte, baris baru ditambahkan untuk kewarasan horisontal.
Sesuatu dari pengiriman kode-golf tercepat-kode kombinasi .
Kompleksitas kasus rata-rata (terburuk?) Tampaknya
O (log n)O (n 0,07 ) . Tidak ada yang saya temukan berjalan lebih lambat dari 0,001, dan saya telah memeriksa seluruh rentang dari 900000000 - 999999999 . Jika Anda menemukan sesuatu yang secara signifikan lebih lama dari itu, ~ 0,1s atau lebih, beri tahu saya.Contoh Penggunaan
Dua terakhir ini tampaknya merupakan kasus terburuk untuk kiriman lainnya. Dalam kedua contoh, solusi yang ditampilkan secara harfiah adalah hal pertama yang diperiksa. Sebab
123456789
, ini yang kedua.Jika Anda ingin menguji berbagai nilai, Anda dapat menggunakan skrip berikut:
Terbaik saat disalurkan ke file. Rentang ini
1..1000000
membutuhkan waktu sekitar 14 detik di komputer saya (nilai 71000 per detik), dan rentang999000000..1000000000
waktu sekitar 20 detik (nilai 50000 per detik), konsisten dengan kompleksitas rata-rata O (log n) .Memperbarui
Sunting : Ternyata algoritma ini sangat mirip dengan yang telah digunakan oleh kalkulator mental selama setidaknya satu abad .
Sejak semula memposting, saya telah memeriksa setiap nilai pada kisaran dari 1..1000000000 . Perilaku 'kasus terburuk' ditunjukkan oleh nilai 699731569 , yang menguji total 190 kombinasi sebelum sampai pada solusi. Jika Anda menganggap 190 sebagai konstanta kecil - dan tentu saja saya lakukan - perilaku terburuk pada rentang yang diperlukan dapat dianggap O (1) . Artinya, secepat mencari solusi dari meja raksasa, dan rata-rata, sangat mungkin lebih cepat.
Satu hal lagi. Setelah 190 iterasi, apapun yang lebih besar dari 144400 bahkan belum berhasil melampaui pass pertama. Logika untuk lintas luas pertama tidak berharga - bahkan tidak digunakan. Kode di atas dapat disingkat sedikit:
Yang hanya melakukan pass pertama pencarian. Kami perlu mengonfirmasi bahwa tidak ada nilai di bawah 144400 yang memerlukan pass kedua, meskipun:
Singkatnya, untuk kisaran 1..1000000000 , solusi waktu hampir konstan ada, dan Anda sedang melihatnya.
Pembaruan yang Diperbarui
@Dennis dan saya telah membuat beberapa peningkatan pada algoritma ini. Anda dapat mengikuti kemajuan dalam komentar di bawah, dan diskusi selanjutnya, jika itu menarik minat Anda. Jumlah rata-rata iterasi untuk rentang yang diperlukan telah turun dari lebih dari 4 ke 1.229 , dan waktu yang dibutuhkan untuk menguji semua nilai untuk 1..1000000000 telah ditingkatkan dari 18m 54s, turun ke 2m 41s. Kasus terburuk yang sebelumnya membutuhkan 190 iterasi; kasus terburuk sekarang, 854382778 , hanya perlu 21 .
Kode Python terakhir adalah sebagai berikut:
Ini menggunakan dua tabel koreksi yang sudah dihitung sebelumnya, satu berukuran 10kb, yang lain 253kb. Kode di atas termasuk fungsi generator untuk tabel ini, meskipun ini mungkin harus dihitung pada waktu kompilasi.
Versi dengan tabel koreksi berukuran lebih sederhana dapat ditemukan di sini: http://codepad.org/1ebJC2OV Versi ini membutuhkan rata-rata 1,620 iterasi per istilah, dengan kasus terburuk 38 , dan seluruh rentang berjalan sekitar 3m 21d. Sedikit waktu dibuat, dengan menggunakan bitwise
and
untuk koreksi b , daripada modulo.Perbaikan
Bahkan nilai lebih cenderung menghasilkan solusi daripada nilai ganjil.
Artikel perhitungan mental yang ditautkan dengan catatan sebelumnya bahwa jika, setelah menghilangkan semua faktor empat, nilai yang akan didekomposisi adalah genap, nilai ini dapat dibagi dua, dan solusi direkonstruksi:
Meskipun ini mungkin masuk akal untuk perhitungan mental (nilai yang lebih kecil cenderung lebih mudah untuk dihitung), itu tidak masuk akal secara algoritmik. Jika Anda mengambil 256 acak 4- tupel, dan memeriksa jumlah modulo 8 kotak , Anda akan menemukan bahwa nilai 1 , 3 , 5 , dan 7 masing-masing mencapai rata-rata 32 kali. Namun, nilai 2 dan 6 masing-masing mencapai 48 kali. Mengalikan nilai aneh dengan 2 akan menemukan solusi, rata-rata, dalam iterasi 33% lebih sedikit. Rekonstruksi adalah sebagai berikut:
Harus diperhatikan bahwa a dan b memiliki paritas yang sama, serta c dan d , tetapi jika solusi ditemukan sama sekali, pemesanan yang tepat dijamin ada.
Jalur yang tidak mungkin tidak perlu diperiksa.
Setelah memilih nilai kedua, b , mungkin sudah tidak mungkin untuk solusi ada, mengingat kemungkinan residu kuadratik untuk setiap modulo yang diberikan. Alih-alih memeriksa, atau beralih ke iterasi berikutnya, nilai b dapat 'dikoreksi' dengan menurunkannya dengan jumlah terkecil yang mungkin mengarah pada solusi. Dua tabel koreksi menyimpan nilai-nilai ini, satu untuk b , dan yang lainnya untuk c . Menggunakan modulo yang lebih tinggi (lebih akurat, menggunakan modulo dengan residu kuadratik yang relatif lebih sedikit) akan menghasilkan peningkatan yang lebih baik. Nilai a tidak perlu koreksi apa pun; dengan memodifikasi n menjadi genap, semua nilaia valid.
sumber
Python 3 (177)
Setelah kita mengurangi input
N
agar tidak habis dibagi 4, itu harus dapat diekspresikan sebagai jumlah empat kotak di mana salah satunya adalah nilai terbesar yang mungkina=int(N**0.5)
atau kurang dari itu, hanya menyisakan sisa kecil untuk jumlah dari tiga kotak lainnya untuk mengurus. Ini sangat mengurangi ruang pencarian.Inilah buktinya nanti kode ini selalu menemukan solusinya. Kami ingin menemukan
a
sehinggan-a^2
adalah jumlah dari tiga kotak. Dari Teorema Tiga-Persegi Legendre , angka adalah jumlah dari tiga kuadrat kecuali jika itu adalah bentuk4^j(8*k+7)
. Khususnya, angka-angka tersebut adalah 0 atau 3 (modulo 4).Kami menunjukkan bahwa tidak ada dua berturut
a
- turut dapat membuat jumlah sisaN-a^2
memiliki bentuk seperti itu untuk kedua nilai berturut-turut .. Kami dapat melakukannya dengan hanya membuat tabela
danN
modulo 4, mencatat bahwaN%4!=0
karena kami telah mengekstraksi semua kekuatan 4 dariN
.Karena tidak ada dua berturut-turut
a
memberi(N-a*a)%4 in [0,3]
, salah satunya adalah aman untuk digunakan. Jadi, kami dengan rakus menggunakan kemungkinan terbesarn
dengann^2<=N
, dann-1
. KarenaN<(n+1)^2
, sisanyaN-a^2
untuk diwakili sebagai jumlah tiga kotak paling banyak(n+1)^2 -(n-1)^2
, yang sama dengan4*n
. Jadi, cukup untuk memeriksa hanya nilai hingga2*sqrt(n)
, yang merupakan kisaran sebenarnyaR
.Seseorang dapat lebih lanjut mengoptimalkan waktu berjalan dengan berhenti setelah satu solusi, menghitung daripada mengulangi nilai terakhir
d
, dan hanya mencari di antara nilai-nilaib<=c<=d
. Tetapi, bahkan tanpa optimasi ini, contoh terburuk yang dapat saya temukan selesai dalam 45 detik pada mesin saya.Rantai "untuk x dalam R" sangat disayangkan. Ini mungkin dapat dipersingkat dengan penggantian string atau penggantian dengan mengulangi indeks tunggal yang mengkodekan (a, b, c, d). Mengimpor itertools ternyata tidak sepadan.
Sunting: Diubah ke
int(2*n**.5)+1
dari2*int(n**.5)+2
untuk menjadikan argumen lebih bersih, jumlah karakter yang sama.sumber
5 => (2, 1, 0, 0)
5 => (2, 1, 0, 0)
menjalankan Ideone 3.2.3 atau di Idle 3.2.2. Mendapatkan apa?5 => (2, 1, 0, 0)
. Apakah Anda bahkan membaca komentarnya? (Sekarang kita memiliki 3 komentar berturut-turut yang memiliki cuplikan kode itu. Bisakah kita tetap melanjutkannya?)5 => (2, 1, 0, 0)
, artinya2^2 + 1^2 + 0^2 + 0^2 = 5
. Jadi, ya, kita bisa.5 => (2, 1, 0, 0)
sudah benar. Contoh-contoh dalam pertanyaan menganggap 0 ^ 2 = 0 menjadi bilangan kuadrat yang valid. Oleh karena itu saya menafsirkan (seperti yang saya pikir xnor lakukan) bahwa Warna Inggris mendapatkan sesuatu yang lain. Warna Inggris, karena Anda tidak merespons lagi, dapatkah kami berasumsi bahwa Anda memang mendapatkannya2,1,0,0
?CJam ,
91907471 byteRingkas, tapi lebih lambat dari pendekatan saya yang lain.
Cobalah online! Tempel Kode , ketik bilangan bulat yang diinginkan di Input dan klik Run .
Latar Belakang
Posting ini dimulai sebagai jawaban GolfScript 99 byte . Sementara masih ada ruang untuk perbaikan, GolfScript tidak memiliki fungsi sqrt bawaan. Saya menyimpan versi GolfScript hingga revisi 5 , karena sangat mirip dengan versi CJam.
Namun, pengoptimalan sejak revisi 6 membutuhkan operator yang tidak tersedia di GolfScript, jadi alih-alih memposting penjelasan terpisah untuk kedua bahasa, saya memutuskan untuk menghentikan versi yang kurang kompetitif (dan jauh lebih lambat).
Algoritma yang diimplementasikan menghitung angka dengan brute force:
Untuk input
m
, cariN
danW
semacamnyam = 4**W * N
.Setel
i = 257**2 * floor(sqrt(N/4))
.Setel
i = i + 1
.Temukan bilangan bulat
j, k, l
sedemikian rupa sehinggai = 257**2 * j + 257 * k + l
, di manak, l < 257
.Periksa apakah
d = N - j**2 - k**2 - l**2
kuadrat sempurna.Jika tidak, dan kembali ke langkah 3.
Cetak
2**W * j, 2**W * k, 2**W * l, 2**W * sqrt(m)
.Contohnya
Pengaturan waktu sesuai dengan Intel Core i7-4700MQ.
Bagaimana itu bekerja
sumber
C, 228
Ini didasarkan pada algoritma pada halaman Wikipedia, yang merupakan kekuatan brutal O (n).
sumber
GolfScript,
133130129 byteCepat, tapi panjang. Baris baru dapat dihapus.
Cobalah online. Perhatikan bahwa penerjemah online memiliki batas waktu 5 detik, jadi itu mungkin tidak berfungsi untuk semua angka.
Latar Belakang
Algoritma mengambil keuntungan dari teorema tiga-persegi Legendre , yang menyatakan bahwa setiap bilangan alami n yang bukan dari bentuk
dapat dinyatakan sebagai jumlah dari tiga kotak.
Algoritme melakukan hal berikut:
Nyatakan nomor sebagai
4**i * j
.Temukan bilangan bulat terbesar
k
sehinggak**2 <= j
danj - k**2
memenuhi hipotesis teorema tiga-persegi Legendre.Setel
i = 0
.Periksa apakah
j - k**2 - (i / 252)**2 - (i % 252)**2
kuadrat sempurna.Jika tidak, tambahkan
i
dan kembali ke langkah 4.Contohnya
Pengaturan waktu sesuai dengan Intel Core i7-4700MQ.
Bagaimana itu bekerja
sumber
j-k-(i/252)-(i%252)
. Dari komentar Anda (saya benar-benar tidak bisa membaca kodenya), sepertinya maksud Andaj-k-(i/252)^2-(i%252)^2
. BTW, setara dengan dij-k-(i/r)^2-(i%r)^2
mana r = sqrt (k) dapat menyimpan beberapa karakter (dan tampaknya bekerja tanpa masalah bahkan untuk k = 0 dalam program C.)j-k^2-(i/252)^2-(i%252)^2
. Saya masih menunggu OP untuk mengklarifikasi apakah 0 adalah input yang valid atau tidak. Program Anda memberi1414 -nan 6 4.000000
masukan0
.0/
=> crash! : P Saya sudah menjalankan rev 1 di laptop saya (i7-4700MQ, 8 GiB RAM). Rata-rata, waktu eksekusi adalah 18,5 detik.Wah 1: C, 190
Ini bahkan lebih haus ingatan daripada rev 0. Prinsip yang sama: buat tabel dengan nilai positif untuk semua jumlah yang mungkin dari 2 kotak (dan nol untuk angka-angka yang bukan jumlah dari dua kotak), kemudian cari.
Dalam rev ini gunakan array
short
alih - alihchar
untuk menyimpan hit, jadi saya bisa menyimpan root dari salah satu dari pasangan kotak di tabel, bukan hanya sebuah bendera. Ini menyederhanakan fungsip
(untuk decoding jumlah 2 kuadrat) karena tidak perlu untuk loop.Windows memiliki batas 2GB pada array. Saya bisa mendapatkan yang dengan
short s[15<<26]
array 1006632960 elemen, cukup untuk memenuhi spesifikasi. Sayangnya, total ukuran program runtime masih lebih 2GB dan (meskipun tweaking pengaturan OS) saya belum dapat menjalankan lebih ukuran ini (meskipun secara teoritis mungkin.) Yang terbaik yang bisa saya lakukan adalahshort s[14<<26]
(939.524.096 elemen.)m*m
Harus benar-benar kurang dari ini (30651 ^ 2 = 939483801.) Namun demikian, program ini berjalan dengan sempurna dan harus bekerja pada OS apa pun yang tidak memiliki batasan ini.Kode tidak dikunci
Rev 0 C, 219
Ini adalah binatang yang haus akan ingatan. Dibutuhkan array 1GB, menghitung semua jumlah yang mungkin dari 2 kotak dan menyimpan bendera untuk masing-masing dalam array. Kemudian untuk input pengguna z, ia mencari array untuk dua jumlah 2 kuadrat a dan za.
fungsi
p
maka reconsitutes kotak asli yang digunakan untuk membuat jumlah dari 2 kotaka
danz-a
dan mencetak mereka, yang pertama dari masing-masing pasangan sebagai integer, yang kedua sebagai ganda (jika memiliki untuk menjadi semua bilangan bulat dua karakter yang dibutuhkan,t
>m=t
.)Program ini memakan waktu beberapa menit untuk membangun tabel jumlah kuadrat (saya pikir ini adalah karena masalah manajemen memori, saya melihat alokasi memori naik perlahan-lahan daripada melompat seperti yang mungkin diharapkan.) Namun begitu itu dilakukan menghasilkan jawaban dengan sangat cepat (jika beberapa angka harus dihitung, program dari
scanf
seterusnya dapat dimasukkan dalam satu lingkaran.kode yang tidak dipisahkan
Contoh output
Yang pertama adalah per pertanyaan. Yang kedua dipilih sebagai yang sulit untuk dicari. Dalam hal ini program harus mencari sejauh 8192 ^ 2 + 8192 ^ 2 = 134217728, tetapi hanya membutuhkan beberapa detik setelah tabel dibangun.
sumber
#include <stdio.h>
(untuk scanf / printf) atau#include <math.h>
(untuk sqrt.) Kompiler menghubungkan perpustakaan yang diperlukan secara otomatis. Saya harus berterima kasih kepada Dennis untuk itu (dia memberi tahu saya tentang pertanyaan ini codegolf.stackexchange.com/a/26330/15599 ) Tip golf terbaik yang pernah saya miliki.include
. Untuk mengkompilasi di Linux, Anda perlu bendera-lm
stdio
dan beberapa perpustakaan lain, tetapi tidakmath
bahkan dengan yanginclude
? Yang saya pahami jika Anda meletakkan flag compiler, Anda tidak memerlukannyainclude
? Yah itu bekerja untuk saya, jadi saya tidak mengeluh, terima kasih lagi atas tipnya. BTW Saya berharap dapat memposting jawaban yang sama sekali berbeda dengan memanfaatkan teorema Legendre (tetapi masih akan menggunakan asqrt
.)-lm
memengaruhi tautan, bukan kompiler.gcc
memilih untuk tidak memerlukan prototipe untuk fungsi yang "diketahuinya", sehingga berfungsi dengan atau tanpa menyertakan. Namun, file header hanya menyediakan prototipe fungsi, bukan fungsi itu sendiri. Di Linux (tetapi bukan Windows, tampaknya), libm perpustakaan matematika bukan bagian dari perpustakaan standar, jadi Anda harus menginstruksikanld
untuk menautkannya.Mathematica, 138 karakterJadi ternyata ini menghasilkan hasil negatif dan imajiner untuk input tertentu seperti yang ditunjukkan oleh edc65 (misalnya, 805306368), jadi ini bukan solusi yang valid. Saya akan meninggalkannya untuk saat ini, dan mungkin, jika saya benar-benar membenci waktu saya, saya akan kembali dan mencoba memperbaikinya.
Atau, tidak berpengalaman:
Saya tidak melihat terlalu keras pada algoritma, tetapi saya berharap ini adalah ide yang sama. Saya baru saja datang dengan solusi yang jelas dan men-tweak itu sampai berhasil. Saya mengujinya untuk semua angka antara 1 dan satu miliar dan ... itu berhasil. Tes hanya membutuhkan sekitar 100 detik pada mesin saya.
Yang menyenangkan tentang ini adalah karena b, c, dan d didefinisikan dengan penugasan yang tertunda
:=
, mereka tidak harus didefinisikan ulang ketika a dikurangi. Ini menyelamatkan beberapa baris tambahan yang saya miliki sebelumnya. Saya mungkin bermain golf lebih jauh dan menyarang bagian-bagian yang berlebihan, tapi inilah konsep pertama.Oh, dan Anda menjalankannya
S@123456789
dan Anda dapat mengujinya dengan{S@#, Total[(S@#)^2]} & @ 123456789
atau# == Total[(S@#)^2]&[123456789]
. Tes lengkap adalahSaya menggunakan pernyataan Print [] sebelumnya tetapi itu banyak memperlambatnya, meskipun tidak pernah dipanggil. Sosok pergi.
sumber
n - a^2 - b^2 - c^2
sebagai variabel dan memeriksa apakahd^2
sama dengan itu.a * 4^(2^k)
untukk>=2
, setelah mengeluarkan semua kekuatan 4 sehinggaa
bukan kelipatan 4 (tetapi bisa genap). Selain itu, masinga
- masing adalah 3 mod 4, atau dua kali angka tersebut. Yang terkecil adalah 192.Haskell 123 + 3 = 126
Gaya kasar sederhana di atas kotak yang sudah dihitung sebelumnya.
Perlu
-O
opsi kompilasi (saya menambahkan 3 karakter untuk ini). Dibutuhkan kurang dari 1 menit untuk kasus terburuk 999950883.Hanya diuji pada GHC.
sumber
C: 198 karakterSaya mungkin bisa memerasnya menjadi lebih dari 100 karakter. Apa yang saya sukai dari solusi ini adalah jumlah minimal sampah, hanya for-loop biasa, melakukan apa yang harus dilakukan untuk-loop (yang gila).
Dan sangat cantik:
Sunting: Tidak cukup cepat untuk semua input, tetapi saya akan kembali dengan solusi lain. Aku akan membiarkan kekacauan operasi ternary ini tetap seperti sekarang.
sumber
Rev B: C, 179
Terima kasih kepada @Dennis untuk perbaikannya. Sisa jawaban di bawah ini tidak diperbarui dari rev A.
Rev A: C, 195
Jauh lebih cepat daripada jawaban saya yang lain dan dengan memori yang jauh lebih sedikit!
Ini menggunakan http://en.wikipedia.org/wiki/Legendre%27s_three-square_theorem . Nomor apa pun yang bukan dari formulir berikut ini dapat dinyatakan sebagai jumlah dari 3 kotak (Saya menyebutnya formulir terlarang):
4^a*(8b+7), or equivalently 4^a*(8b-1)
Perhatikan bahwa semua angka kuadrat aneh adalah bentuk
(8b+1)
dan semua angka kuadrat genap bentuk4b
. Namun ini menyembunyikan fakta bahwa semua bilangan genap adalah bentuk4^a*(odd square)==4^a*(8b+1)
. Akibatnya2^x-(any square number < 2^(x-1))
untuk ganjilx
akan selalu dalam bentuk terlarang. Karenanya angka-angka ini dan kelipatannya adalah kasus yang sulit, itulah sebabnya mengapa banyak program di sini membagi 4 kekuatan sebagai langkah pertama.Sebagaimana dinyatakan dalam jawaban @ xnor,
N-a*a
tidak dapat berupa formulir terlarang untuk 2 nilai berturut-turut daria
. Di bawah ini saya menyajikan bentuk mejanya yang disederhanakan. Selain fakta bahwa setelah pembagian dengan 4N%4
tidak dapat sama dengan 0, perhatikan bahwa hanya ada 2 nilai yang mungkin untuk(a*a)%4
.Jadi, kami ingin menghindari nilai-nilai
(N-a*a)
yang mungkin dari bentuk terlarang, yaitu yang mana(N-a*a)%4
adalah 3 atau 0. Seperti dapat dilihat ini tidak dapat terjadi untuk hal yang samaN
dengan ganjil dan genap(a*a)
.Jadi, algoritma saya berfungsi seperti ini:
Saya terutama menyukai cara saya melakukan langkah 3. Saya menambahkan 3
N
, sehingga pengurangan diperlukan jika(3+N-a*a)%4 =
3 atau 2. (tetapi tidak 1 atau 0.) Bagi ini dengan 2 dan seluruh pekerjaan dapat dilakukan dengan ekspresi yang cukup sederhana .Kode tidak dikunci
Perhatikan
for
loop tunggalq
dan gunakan pembagian / modulo untuk mendapatkan nilai darib
danc
dari itu. Saya mencoba menggunakana
sebagai pembagi bukan 256 untuk menghemat byte, tetapi kadang-kadang nilaia
tidak benar dan program digantung, mungkin tanpa batas. 256 adalah kompromi terbaik yang bisa saya gunakan>>8
alih-alih/256
untuk divisi.Keluaran
Sebuah kekhasan yang menarik adalah bahwa jika Anda memasukkan angka kuadrat,
N-(a*a)
= 0. Tetapi program mendeteksi bahwa0%4
= 0 dan penurunan ke persegi berikutnya ke bawah. Akibatnya, input bilangan persegi selalu didekomposisi menjadi sekelompok kotak yang lebih kecil kecuali jika mereka berbentuk4^x
.sumber
m=1
sebelumnyamain
. 2. Jalankanscanf
dalamfor
pernyataan. 3. Gunakanfloat
sebagai gantidouble
. 4.n%4<1
lebih pendek dari!(n%4)
. 5. Ada ruang usang dalam string format printf.n-=a*a
tidak berfungsi, karenaa
dapat dimodifikasi sesudahnya (ini memberikan beberapa jawaban yang salah dan menggantung pada sejumlah kecil kasus, seperti 100 + 7 = 107). Saya memasukkan semua yang lainnya. Akan menyenangkan untuk sesuatu untuk mempersingkatprintf
tapi saya pikir satu-satunya jawaban adalah mengubah bahasa. Kunci kecepatan adalah untuk menetapkan nilai yang baik dengana
cepat. Ditulis dalam C dan dengan ruang pencarian kurang dari 256 ^ 2, ini mungkin program tercepat di sini.printf
pernyataan tampaknya sulit tanpa menggunakan makro atau array, yang akan menambah bulk di tempat lain. Mengubah bahasa tampaknya merupakan cara "mudah". Pendekatan Anda akan menimbang 82 byte dalam CJam.JavaScript -
175 191 176173 karakterKekuatan kasar, tapi cepat.
Edit Cepat tetapi tidak cukup untuk beberapa input yang tidak menyenangkan. Saya harus menambahkan langkah pertama pengurangan dengan mengalikan 4.
Sunting 2 Singkirkan fungsi, keluaran di dalam loop lalu paksa keluar kontisi
Sunting 3 0 bukan input yang valid
Tidak Disatukan:
Contoh output
sumber