รับ 39 ไบต์
นี่คือคำอธิบายว่าฉันได้โซลูชัน 39 ไบต์ซึ่งเดนนิสและโจนาธานเฟรชพบได้อย่างไรเช่นกัน หรือมากกว่านั้นอธิบายว่าใครจะได้คำตอบในการเข้าใจถึงปัญหาย้อนหลังในลักษณะที่ดีกว่าเส้นทางที่แท้จริงของฉันไปซึ่งเป็นเหตุผลที่เต็มไปด้วยโคลนและการตายที่สิ้นสุด
n=0
exec"print n;n=n+2^-(n+2^n)%3;"*400
เขียนนี้น้อย golfed และมี parens เพิ่มเติมดูเหมือนว่า:
n=0
for _ in range(400):
print n
n=(n+2)^(-((n+2)^n))%3
ความเท่าเทียมกันบิต
เราเริ่มต้นด้วยแนวคิดจากโซลูชัน 47 ไบต์ของฉันเพื่อแสดงตัวเลขทั้งหมดในแบบฟอร์มn=2*k+b
ที่k
นับขึ้น0,1,...,399
และb
เป็นบิตพาริตีที่ทำให้จำนวนโดยรวมของ 1 เป็นเท่ากัน
ลองเขียนpar(x)
สำหรับความเท่าเทียมกันบิตของx
ที่เป็นแฮคเกอร์ ( ^
) x
ทั้งหมดของบิตใน นี่คือ 0 ถ้ามีจำนวน 1 บิต (เลขเป็นชั่ว) และ 1 ถ้ามีเลข 1 บิตคี่ สำหรับn=2*k+b
เรามีpar(n) = par(k)^b
เพื่อให้บรรลุความชั่วร้ายที่par(n)==0
เราต้องการb=par(k)
คือบิตสุดท้ายของn
การเป็นบิตพาริตี้ของบิตก่อนหน้านี้
ความพยายามครั้งแรกของฉันในการเล่นกอล์ฟอยู่บนการแสดงpar(k)
, เป็นครั้งแรกที่ได้โดยตรงด้วยbin(k).count('1')%2
และจากนั้นมีการจัดการบิต
อัพเดตพาริตี
ถึงกระนั้นก็ไม่ได้มีการแสดงออกสั้น ๆ แต่มันช่วยให้ตระหนักว่ามีข้อมูลมากขึ้นที่จะทำงานกับ แทนที่จะคำนวณบิตพาริตี้ของตัวเลขปัจจุบัน
k ----> par(k)
เราสามารถอัปเดตความเท่าเทียมกันบิตในขณะที่เราเพิ่มไปk
k+1
k ----> par(k)
|
v
k+1 ----> par(k+1)
นั่นคือเนื่องจากเรากำลังนับk=0,1,2,...
เราเพียงแค่ต้องรักษาบิตพาริตี้ปัจจุบันแทนที่จะคำนวณจากรอยขีดข่วนในแต่ละครั้ง การปรับปรุงความเท่าเทียมกันของบิตpar(k+1)^par(k)
คือความเท่าเทียมกันของจำนวนบิตที่พลิกจากk
ไปk+1
เป็นpar((k+1)^k)
กล่าวคือ
par(k+1) ^ par(k) = par((k+1)^k)
par(k+1) = par(k) ^ par((k+1)^k)
รูปแบบของ (k+1)^k
par((k+1)^k)
ตอนนี้เราต้องคำนวณ อาจดูเหมือนว่าเราไม่ได้อยู่ที่ใดเพราะการคำนวณบิตพาริตี้เป็นปัญหาที่เราพยายามแก้ไข แต่ตัวเลขที่แสดงเป็น(k+1)^k
มีรูปแบบ1,3,7,15,..
ที่เป็นหนึ่งด้านล่างอำนาจของ 2, ความจริงมักจะใช้ในการแฮ็กบิต เรามาดูเหตุผลว่าทำไม
เมื่อเราเพิ่มขึ้นk
เอฟเฟกต์ของไบนารี่ก็จะกลับด้านสุดท้าย0
และ1
ไปทางขวาเพื่อสร้างผู้นำใหม่0
หากไม่มีเลย ยกตัวอย่างเช่นk=43=0b101011
**
101011 (43)
+ 1
------
= 101100 (44)
101011 (43)
^101100 (44)
------
= 000111 (77)
*
คอลัมน์ก่อให้เกิดการพกมีเครื่องหมาย เหล่านี้มี1
การเปลี่ยนแปลงไป0
และผ่านในบิตของการพกพา1
ซึ่งช่วยให้การขยายพันธุ์ที่เหลือจนกว่าจะฮิต0
ในซึ่งการเปลี่ยนแปลงไปk
1
บิตใด ๆ ที่อยู่ทางด้านซ้ายจะไม่ได้รับผลกระทบ ดังนั้นเมื่อk^(k+1)
ตรวจสอบตำแหน่งบิตที่เปลี่ยนk
ไปk+1
จะพบว่าตำแหน่งของขวาสุด0
และ1
ขวาไป นั่นคือบิตที่เปลี่ยนแปลงเป็นส่วนต่อท้ายดังนั้นผลลัพธ์คือ 0 ตามด้วยหนึ่งหรือมากกว่า 1 ของ หากไม่มีศูนย์นำหน้าจะมีเลขฐานสอง1, 11, 111, 1111, ...
ที่อยู่ต่ำกว่ากำลังสอง
การคำนวณ par((k+1)^k)
ตอนนี้เราเข้าใจแล้วว่า(k+1)^k
มี จำกัด1,3,7,15,...
เราลองหาวิธีคำนวณความเท่าเทียมกันของตัวเลขเหล่านี้ นี่เป็นความจริงที่มีประโยชน์คือว่า1,2,4,8,16,...
โมดูโลสลับ3
ระหว่าง1
และตั้งแต่2
2==-1 mod 3
ดังนั้นการให้1,3,7,15,31,63...
โมดูโล่3
ให้1,0,1,0,1,0...
ซึ่งเป็นบิต parities ของพวกเขา ที่สมบูรณ์แบบ!
ดังนั้นเราสามารถทำการอัปเดตpar(k+1) = par(k) ^ par((k+1)^k)
เป็น
par(k+1) = par(k) ^ ((k+1)^k)%3
การใช้b
เป็นตัวแปรที่เราจัดเก็บพาริตี้อยู่จะมีลักษณะดังนี้
b^=((k+1)^k)%3
การเขียนรหัส
วางนี้ร่วมกันในรหัสที่เราจะเริ่มต้นk
และความเท่าเทียมกันบิตb
ทั้งที่0
แล้วพิมพ์ซ้ำ ๆn=2*k+b
และการปรับปรุงและb=b^((k+1)^k)%3
k=k+1
46 ไบต์
k=b=0
exec"print 2*k+b;b^=(k+1^k)%3;k+=1;"*400
ลองออนไลน์!
เราลบ parens รอบk+1
ใน((k+1)^k)%3
เพราะงูใหญ่มีความสำคัญไม่นอกจากครั้งแรกแล้วแปลกเป็นลักษณะ
การปรับปรุงรหัส
เราสามารถทำได้ดีกว่าโดยการทำงานกับตัวแปรเดี่ยวโดยตรงn=2*k+b
และทำการอัปเดตโดยตรง ทำสอดคล้องกับk+=1
n+=2
และการปรับปรุงที่สอดคล้องกับb^=(k+1^k)%3
n^=(k+1^k)%3
ที่นี่ก่อนที่จะอัพเดตk=n/2
n
44 ไบต์
n=0
exec"print n;n^=(n/2+1^n/2)%3;n+=2;"*400
ลองออนไลน์!
เราสามารถย่อให้สั้นลงn/2+1^n/2
(จำได้ว่านี่คือ(n/2+1)^n/2
) โดยเขียนใหม่
n/2+1 ^ n/2
(n+2)/2 ^ n/2
(n+2 ^ n)/2
ตั้งแต่/2
ลบบิตสุดท้ายมันไม่สำคัญว่าเราจะทำก่อนหรือหลัง xor-ing n^=(n+2^n)/2%3
ดังนั้นเรามี เราสามารถบันทึกไบต์อื่นโดยสังเกตว่าโมดูโล3
, /2
เทียบเท่ากับ*2
เทียบเท่ากับการ-
สังเกตว่าn+2^n
เป็นแม้ดังนั้นส่วนที่เป็นลดลงครึ่งหนึ่งที่เกิดขึ้นจริงโดยไม่ต้องปูพื้น สิ่งนี้จะช่วยให้n^=-(n+2^n)%3
41 ไบต์
n=0
exec"print n;n^=-(n+2^n)%3;n+=2;"*400
ลองออนไลน์!
ในที่สุดเราสามารถรวมการดำเนินการn^=c;n+=2
เข้าn=(n+2)^c
ด้วยกันซึ่งc
เป็นบิต วิธีนี้ใช้งานได้เพราะ^c
ทำหน้าที่เฉพาะบิตสุดท้ายและ+2
ไม่สนใจบิตสุดท้ายดังนั้นการดำเนินการเดินทาง อีกครั้งมีความสำคัญช่วยให้เราละเว้น parens n=n+2^c
และเขียน
39 ไบต์
n=0
exec"print n;n=n+2^-(n+2^n)%3;"*400
ลองออนไลน์!