Retina , 530 220 210 202 201 193 191 187 185 (184) byte
Kredit ke randomra untuk menghemat 3 byte! (Dan membuka jalan untuk beberapa lagi.)
+`\.(\d)(.+)( .+)
$1.$2_$3_
\b
#
+`(\d*)#((((((((((9)|8)|7)|6)|5)|4)|3)|2)|1)|\w)
$1$1$1$1$1$1$1$1$1$1$3$4$5$6$7$8$9$10$11#
\d
11
(?=(1*)\1)[^.]
$1
^(1+)\.\1{90000}1+
Retina!
1.+
Trash!
Untuk keperluan penghitungan byte, setiap baris menggunakan file terpisah, tetapi Anda dapat menjalankan kode di atas seperti dari satu file dengan memanggil Retina dengan -s
flag.
Ini mengharapkan kepadatan pertama (yang harus mengandung titik desimal, bahkan jika itu trailing), diikuti oleh lebar dan tinggi, yaitu d w h
.
Ini agak lambat. Saya tidak akan mencoba sebagian besar kasus uji yang diberikan, karena akan berjalan lama. Namun, Anda dapat memeriksa apakah itu berfungsi dengan benar dengan kasus uji
19. 4096 2160 -> Trash!
1. 180 240 -> Trash!
1. 181 240 -> Retina!
1. 180 241 -> Retina!
0.04 10 10 -> Retina!
Pada dasarnya, setelah mengalikan semua angka hingga menjadikan kerapatan bilangan bulat, Anda tidak ingin lebar dan tinggi memiliki lebih dari 4 digit.
Meskipun ini lambat, itu sepenuhnya tepat ... tidak ada masalah floating point atau sesuatu seperti itu. Semua aritmatika menggunakan bilangan bulat (unary).
Pada prinsipnya, saya bisa mengurangi satu byte lagi: byte ^
dapat dihilangkan, tetapi itu akan membuat Trash!
kasus uji sangat lambat karena jumlah backtracking yang berlebihan.
Penjelasan
Pertama, mari kita atur ulang ketimpangan untuk menghindari operasi floating point:
√(w2 + h2) / d > 300
√(w2 + h2) > 300 d
w2 + h2 > 90000 d2
Kami juga dapat melihat bahwa ini tidak berubah di bawah penggandaan w
, h
dan d
dengan nomor yang sama x
:
w2 + h2 > 90000 d2
(x w)2 + (x h)2 > 90000 (x d)2
x2 (w2 + h2) > 90000 x2 d2
w2 + h2 > 90000 d2
Ada beberapa cara untuk mengkuadratkan angka unary, tetapi kami akan menggunakan identitas itu
n2 = Σi=1..2n ⌊i/2⌋
Ini memberi kita cara untuk menyelesaikan masalah hanya menggunakan bilangan bulat aritmatika (mewakili bilangan bulat di unary).
Mari kita lihat kodenya. Setiap pasangan garis adalah pengganti regex.
+`\.(\d)(.+)( .+)
$1.$2_$3_
Ini berulang kali memindahkan titik desimal dalam kepadatan ke kanan sambil mengalikan lebar dan tinggi dengan 10 (di x
atas). Ini untuk memastikan bahwa semua angka adalah bilangan bulat. Alih-alih menambahkan nol, saya menambahkan _
, yang saya akan memperlakukan sebagai nol nanti. (Ini adalah trik golf, karena kalau tidak saya harus menulis ...${3}0
untuk menghindari ambiguitas dengan $30
.) Di +
depan regex memberitahu Retina untuk mengulangi penggantian ini sampai hasilnya berhenti berubah (yang merupakan kasus ketika polanya tidak lagi cocok) .
\b
#
Kami sedang menyiapkan tiga angka untuk konversi ke unary sekarang. Pada prinsipnya, kita membutuhkan penanda (di #
) di depan setiap angka, tetapi lebih pendek untuk menambahkan satu ke akhir setiap angka juga, yang tidak akan mempengaruhi langkah konversi.
+`(\d*)#((((((((((9)|8)|7)|6)|5)|4)|3)|2)|1)|\w)
$1$1$1$1$1$1$1$1$1$1$3$4$5$6$7$8$9$10$11#
Ini adalah konversi ke unary, menggunakan trik yang telah dikembangkan oleh dan1111 . Pada dasarnya saya menerjemahkan setiap digit ke rep-digit sendiri, sambil mengalikan digit yang ada dengan 10 (memindahkan #
marker ke kanan dalam proses). Representasi biner ini akan menjadi campuran yang berbeda dari angka-angka yang berbeda, tetapi jumlah totalnya akan sama dengan nilai integer asli. Perhatikan \w
pada bagian akhir - biasanya ini hanya saja 0
, tetapi kami juga ingin memperlakukannya _
sebagai nol (yang dianggap sebagai karakter kata dalam regex).
\d
11
Kami mengubah setiap digit menjadi dua 1
s, dengan demikian a) memastikan semua digit adalah sama (yang akan diperlukan nanti) dan b) menggandakan masing-masing angka.
(?=(1*)\1)[^.]
$1
Ini melakukan dua hal: itu menguadratkan semua angka (atau lebih tepatnya setengah dari setiap angka, dengan menghitung jumlah di atas 2n
), dan menambahkan kuadrat yang dihasilkan dari lebar dan tinggi. Perhatikan bahwa [^.]
cocok 1
dengan, #
spidol dan spasi. Jika a #
atau spasi, lookahead tidak akan menangkap apa pun, yang berarti semua itu hanya dihapus, yaitu hasil untuk lebar dan tinggi digabungkan / ditambahkan. Titik desimal .
tetap memisahkan hasil d
dari itu. Jika [^.]
cocok dengan 1
sebaliknya, maka lookahead memastikan bahwa kami menangkap setengah dari 1
setelah itu (dibulatkan ke bawah) dalam grup 1
. Ini menghitung jumlah yang saya sebutkan di atas, yang kemudian akan menghasilkan kuadrat dari angka aslinya.
^(1+)\.\1{90000}1+
Retina!
String sekarang (di unary), lalu , lalu (di unary). Kami ingin tahu apakah angka unary pertama kali lebih pendek dari yang kedua. Kita dapat dengan mudah melakukan perkalian ini menggunakan capturing group dan sintaks pengulangan. Kami menggunakan (bukan ) setelah itu untuk memastikan bahwa angka kedua sebenarnya lebih besar dari itu dan tidak hanya sama. Jika demikian, kami mengganti semua itu dengan .d2
.
w2 + h2
90000
{n}
1+
1*
Retina!
1.+
Trash!
Jika angka kedua tidak cukup besar, maka langkah sebelumnya tidak akan mengubah apa pun dan string akan tetap dimulai dengan a 1
. Jika itu masalahnya, kami hanya mengganti seluruh string dengan Trash!
dan selesai.