รับ 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)
เราสามารถอัปเดตความเท่าเทียมกันบิตในขณะที่เราเพิ่มไปkk+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)%3k=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/2n
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
ลองออนไลน์!