Mendapatkan 39 byte
Ini adalah penjelasan tentang bagaimana saya mendapatkan solusi 39-byte, yang ditemukan Dennis dan JonathanFrech secara terpisah. Atau, lebih tepatnya, itu menjelaskan bagaimana seseorang bisa sampai pada jawaban di belakang, dengan cara yang jauh lebih baik daripada jalan saya yang sebenarnya untuk itu, yang penuh dengan alasan berlumpur dan jalan buntu.
n=0
exec"print n;n=n+2^-(n+2^n)%3;"*400
Menulis ini sedikit kurang golf dan dengan lebih banyak parens, ini seperti:
n=0
for _ in range(400):
print n
n=(n+2)^(-((n+2)^n))%3
Paritas bit
Kita mulai dengan sebuah ide dari solusi 47-byte saya untuk menampilkan semua angka dari formulir di n=2*k+b
mana k
dihitung 0,1,...,399
dan b
merupakan bit paritas yang membuat angka keseluruhan 1 genap.
Mari kita menulis par(x)
untuk bit paritas dari x
, itu adalah xor ( ^
) semua bit dalam x
. Ini adalah 0 jika ada angka genap 1-bit (angka itu jahat), dan 1 jika ada angka ganjil 1-bit. Karena n=2*k+b
, kita harus par(n) = par(k)^b
, untuk mencapai kejahatan yang par(n)==0
kita butuhkan b=par(k)
, yaitu bit terakhir n
untuk menjadi bit paritas bit sebelumnya.
Upaya pertama saya dalam bermain golf adalah mengekspresikan par(k)
, pertama langsung dengan bin(k).count('1')%2
, dan kemudian dengan sedikit manipulasi .
Pembaruan paritas
Tetap saja, sepertinya tidak ada ekspresi pendek. Alih-alih, itu membantu untuk menyadari bahwa ada lebih banyak info untuk dikerjakan. Daripada hanya menghitung paritas bit dari angka saat ini,
k ----> par(k)
kita dapat memperbarui paritas bit seperti yang kita kenaikan k
untuk k+1
.
k ----> par(k)
|
v
k+1 ----> par(k+1)
Yaitu, karena kita menghitung k=0,1,2,...
, kita hanya perlu mempertahankan paritas bit saat ini daripada menghitungnya dari awal setiap kali. Update bit paritas par(k+1)^par(k)
adalah paritas dari jumlah bit membalik untuk pergi dari k
ke k+1
, yang par((k+1)^k)
.
par(k+1) ^ par(k) = par((k+1)^k)
par(k+1) = par(k) ^ par((k+1)^k)
Bentuk dari (k+1)^k
Sekarang kita perlu menghitung par((k+1)^k)
. Sepertinya kita tidak mendapatkan apa-apa karena menghitung bit parity adalah masalah yang ingin kita pecahkan. Tapi, angka-angka yang dinyatakan (k+1)^k
memiliki bentuk 1,3,7,15,..
, yaitu satu di bawah kekuatan 2, fakta yang sering digunakan dalam peretasan bit . Mari kita lihat mengapa begitu.
Ketika kita bertambah k
, efek dari binary carry adalah membalikkan yang terakhir 0
dan semuanya 1
ke kanan, menciptakan pemimpin baru 0
jika tidak ada. Sebagai contoh, ambilk=43=0b101011
**
101011 (43)
+ 1
------
= 101100 (44)
101011 (43)
^101100 (44)
------
= 000111 (77)
Kolom yang menyebabkan carry ditandai dengan *
. Ini memiliki 1
perubahan ke 0
dan meneruskan sedikit carry 1
, yang terus menyebar ke kiri sampai menyentuh 0
dalam k
, yang berubah menjadi 1
. Setiap bit lebih jauh ke kiri tidak terpengaruh. Jadi, ketika k^(k+1)
cek yang sedikit posisi berubah k
untuk k+1
, ia menemukan posisi paling kanan 0
dan 1
's untuk yang benar. Yaitu, bit yang diubah membentuk akhiran, jadi hasilnya 0's diikuti oleh satu atau lebih 1's. Tanpa nol terkemuka, ada angka biner 1, 11, 111, 1111, ...
yang satu di bawah kekuatan 2.
Komputasi par((k+1)^k)
Sekarang kita mengerti bahwa (k+1)^k
terbatas 1,3,7,15,...
, mari kita cari cara untuk menghitung bit paritas dari angka-angka tersebut. Di sini, fakta yang berguna adalah 1,2,4,8,16,...
modulo alternatif itu 3
antara 1
dan 2
, sejak 2==-1 mod 3
. Jadi, mengambil memberi 1,3,7,15,31,63...
modulo , yang persis paritas bit mereka. Sempurna!3
1,0,1,0,1,0...
Jadi, kita bisa melakukan pembaruan par(k+1) = par(k) ^ par((k+1)^k)
sebagai
par(k+1) = par(k) ^ ((k+1)^k)%3
Menggunakan b
sebagai variabel tempat kita menyimpan paritas, ini terlihat seperti
b^=((k+1)^k)%3
Menulis kodenya
Menyatukan ini dalam kode, kita mulai k
dan paritas b
keduanya 0
, kemudian berulang kali mencetak n=2*k+b
dan memperbarui b=b^((k+1)^k)%3
dan k=k+1
.
46 byte
k=b=0
exec"print 2*k+b;b^=(k+1^k)%3;k+=1;"*400
Cobalah online!
Kami menghapus parens k+1
di sekitar ((k+1)^k)%3
karena prioritas Python melakukan penambahan pertama, aneh seperti yang terlihat.
Perbaikan kode
Kita bisa melakukan yang lebih baik dengan bekerja secara langsung dengan satu variabel n=2*k+b
dan melakukan pembaruan langsung di atasnya. Melakukan k+=1
sesuai dengan n+=2
. Dan, memperbarui b^=(k+1^k)%3
berkorespondensi dengan n^=(k+1^k)%3
. Di sini, k=n/2
sebelum memperbarui n
.
44 byte
n=0
exec"print n;n^=(n/2+1^n/2)%3;n+=2;"*400
Cobalah online!
Kita dapat mempersingkat n/2+1^n/2
(ingat ini (n/2+1)^n/2
) dengan menulis ulang
n/2+1 ^ n/2
(n+2)/2 ^ n/2
(n+2 ^ n)/2
Sejak /2
menghapus bit terakhir, tidak masalah jika kita melakukannya sebelum atau sesudah xor-ing. Jadi, sudah n^=(n+2^n)/2%3
. Kita dapat menyimpan byte lain dengan mencatat modulo itu 3
, /2
sama dengan *2
ekivalen dengan -
, mencatat bahwa n+2^n
meskipun demikian pembagiannya adalah separuh sebenarnya tanpa lantai. Ini memberin^=-(n+2^n)%3
41 byte
n=0
exec"print n;n^=-(n+2^n)%3;n+=2;"*400
Cobalah online!
Akhirnya, kita bisa menggabungkan operasi n^=c;n+=2
menjadi n=(n+2)^c
, di mana c
ada sedikit. Ini berfungsi karena ^c
hanya bertindak pada bit terakhir dan +2
tidak peduli dengan bit terakhir, jadi operasi pun jadi. Sekali lagi, diutamakan mari kita hilangkan orangtua dan menulis n=n+2^c
.
39 byte
n=0
exec"print n;n=n+2^-(n+2^n)%3;"*400
Cobalah online!