จะหาองค์ประกอบของลำดับ Digit Sum ได้อย่างมีประสิทธิภาพได้อย่างไร


20

เพิ่งหมดความสนใจฉันพยายามที่จะแก้ปัญหาจากหมวด "ล่าสุด" ของ Project Euler ( ลำดับ Digit Sum ) แต่ฉันไม่สามารถคิดวิธีแก้ปัญหาได้อย่างมีประสิทธิภาพ ปัญหามีดังต่อไปนี้ (ในลำดับคำถามดั้งเดิมมีสองรายการที่เริ่มต้น แต่ไม่เปลี่ยนลำดับ):

ลำดับ Digit Sum คือ 1,2,4,8,16,23,28,38,49 .... โดยที่ลำดับของลำดับคือผลรวมของตัวเลขที่อยู่ก่อนหน้าในลำดับ ค้นหาคำศัพท์ลำดับที่ลำดับnเสื้อชั่วโมง1015เสื้อชั่วโมง

โซลูชันไร้เดียงสาไม่สามารถใช้งานได้เนื่องจากใช้เวลานาน ฉันพยายามลดปัญหาให้เป็นกรณีของการยกกำลังเมทริกซ์ (ซึ่งใช้เวลา )) แต่ไม่สามารถเกิดขึ้นได้กับการเกิดซ้ำที่เหมาะสมกับเกณฑ์เชิงเส้นเนื่องจากการเกิดซ้ำสำหรับลำดับนี้คือ ค่อนข้างแปลก จะเห็นได้ว่าลำดับถูกควบคุมโดยการเกิดซ้ำ:O(ล.โอก.(1015))

an=an1+d(an1).....(1)

โดยที่คือคำของลำดับและคือฟังก์ชันซึ่งเมื่อได้รับจำนวนธรรมชาติเป็นอินพุตจะส่งคืนผลรวมของตัวเลขของตัวเลข (เช่น. ) วิธีที่สองของฉันคือพยายามหารูปแบบบางอย่างในลำดับ จะเห็นได้ว่าคำสองสามคำแรกของลำดับสามารถเขียนเป็นn t h dannthdd(786)=21

   a_1 = 1  
   a_2 = 1 + d( 1 )
   a_3 = 1 + d( 1 ) + d( 1 + d( 1 ) )
   a_4 = 1 + d( 1 ) + d( 1 + d( 1 ) ) + d( 1 + d( 1 ) + d( 1 + d( 1 ) ) )
   a_5 = 1 + d( 1 ) + d( 1 + d( 1 ) ) + d( 1 + d( 1 ) + d( 1 + d( 1 ) ) ) + d( 1 +  d(  
   1 ) + d( 1 + d( 1 ) ) + d( 1 + d( 1 ) + d( 1 + d( 1 ) ) ) )

จากรูปแบบข้างต้นกลายเป็นคำที่ของลำดับสามารถสร้างขึ้นได้ด้วยวิธีการต่อไปนี้:nth

  1. เขียนพร้อมสัญลักษณ์เพิ่มเติมระหว่างกัน 12n1 1
  2. ออกจากแรกจากนั้นจึงใช้ฟังก์ชัน ในอีกข้อกำหนดและอีกคำต่อจากนั้นในอีกข้อกำหนดและต่อไปd 2 0 2 1 2 21d202122
  3. จากนั้นใช้วิธีการข้างต้นซ้ำกับข้อโต้แย้งของแต่ละฟังก์ชั่นใช้d

เช่นถ้า n = 3 เราดำเนินการจัดการต่อไปนี้:

    1 + 1 + 1 + 1 + 1 + 1 + 1 + 1
    1 + d( 1 ) + d( 1 + 1 ) + d( 1 + 1 + 1 + 1 )
    1 + d( 1 ) + d( 1 + d(1) ) + d( 1 + d( 1 ) + d( 1 +d( 1 ) ) )

ด้วยการเขียนโปรแกรมแบบไดนามิกฉันสามารถสร้างคำศัพท์โดยใช้วิธีการข้างต้นในเวลาซึ่งอีกครั้งไม่ได้ดีกว่าโซลูชั่นไร้เดียงสาnthO(log(21015))

แก้ไข 1
อีกสิ่งหนึ่งที่สามารถสังเกตได้คือว่า{n-1}) ยกตัวอย่างเช่น 5 แต่ฉันไม่สามารถใช้ประโยชน์จากจุดนี้ได้ ฉันพยายามค้นหาความสัมพันธ์การเกิดซ้ำเชิงเส้นอีกครั้ง (สำหรับการยกกำลังเมทริกซ์) แต่ฉันหามันไม่เจอd(an)=d(2n-1)d(a6)=d(23)=d(32)=5

แก้ไข 2

ต่อไปนี้เป็นกราฟเมื่อมีการพล็อตลำดับสำหรับช่วงที่เล็กลง (คำแรกของลำดับจะถูกพล็อต) 106ป้อนคำอธิบายรูปภาพที่นี่

PS: ฉันรู้ว่าไม่แนะนำให้ขอคำแนะนำจาก Project Euler แต่ฉันต้องการทิศทางใหม่หรือคำใบ้เนื่องจากฉันได้ย้ายเป็นวงกลมในไม่กี่วันที่ผ่านมา หากไม่เป็นที่ยอมรับฉันสามารถลบคำถามได้หากแนะนำ


1
ฉันรู้สึกว่าYou are given a106 = 31054319.ในปัญหาออยเลอร์ดั้งเดิมเป็นคำใบ้
Filip Haglund

@FilipHaglund ที่ไม่ใช่คำใบ้ ด้วยแรงเดรัจฉานเพียงอย่างเดียวฉันสามารถคำนวณค่าได้ง่าย มันเป็นเพียงการตรวจสอบแนวทางของคุณ
sashas

3
นอกจากนี้ใน OEIS: oeis.org/A004207
Yuval Filmus

@EvilJS สามารถใช่ฉันวางแผนกราฟเพื่อขยายมันจะค่อยๆเพิ่มขึ้นในรูปแบบซิกแซก คุณช่วยอธิบายจุดสุดท้ายของคุณ "" รูปแบบการแคชได้ไหม .. ".
sashas

เมื่อรูปแบบที่น่าสนใจปรากฏเป็น mod 9 สิ่งใดที่น่าสนใจเกิดขึ้นถ้าเราดูตามลำดับ mod 11 หรือ mod 99? ค่า mod 11 สามารถได้มาจากผลรวมของเลขคี่ที่ทำดัชนีและผลรวมของเลขคู่ที่ทำดัชนี ค่า mod 99 สามารถหาได้จากผลรวมของจำนวนคู่ที่อยู่ติดกัน
DW

คำตอบ:


4

ลำดับของคุณอธิบายไว้ในoeis.org/A004207เป็นผลรวมหลัก มีบางจุดที่ดีเช่นลำดับ mod 9 มีรูปแบบการทำซ้ำหุ้นมันรากดิจิตอลที่มีoeis.org/A065075และoeis.org/A001370 หากคุณสมบัติเหล่านั้นมีประโยชน์คือปัญหาเปิด (เพราะไม่มีสมการรูปแบบปิดสำหรับหมายเลข n - t h )(1,2,4,8,7,5)n-เสื้อชั่วโมง

มีคุณสมบัติบางอย่างของลำดับนี้ที่ควรกล่าวถึง:
เมื่อคุณคำนวณคุณต้องเก็บเฉพาะตัวนับ (เพื่อทราบว่าเป็นตัวเลขใด) และจำนวนตัวเอง ในการเริ่มต้นใหม่ไม่จำเป็นต้องมีอะไรอีกเพราะหมายเลขถัดไปคือหมายเลขปัจจุบัน + ผลรวมของตัวเลขn-เสื้อชั่วโมง

ทำตามขั้นตอนบางอย่างเพื่อให้มั่นใจความเร็วในตอนแรกมันเป็นการดีที่จะใส่ตัวเลขลงในอาร์เรย์หลีกเลี่ยงการคำนวณที่ไร้เดียงสาและการหย่าร้างซึ่งมีราคาแพง สิ่งนี้จะช่วยให้การเร่งความเร็วเป็นไปอย่างรวดเร็ว แต่เมื่อพิจารณาในบางครั้ง

จากจุดเริ่มต้นคุณสามารถคำนวณจุดต่อไปและจุดต่อไปและใช้ได้จนถึงบางจุดจุดนี้คือการเปลี่ยนแปลงจำนวนหลัก
สิ่งที่สำคัญกว่าคือรูปแบบที่เปลี่ยนแปลงไปตามจำนวนที่เพิ่มขึ้น
ผลรวมหลักมีขนาดเล็กเมื่อเปรียบเทียบกับตัวเลขดังนั้นเฉพาะส่วนของตัวเลขที่จะเปลี่ยนแปลงในการดำเนินการส่วนใหญ่
แล้วเราจะแคชอะไรจริงๆ

เรารู้ว่าด้วยตัวเลขสองตัวที่มีผลรวมหลักเดียวกันการเพิ่มเพื่อรับหมายเลขถัดไปจะเหมือนกัน แล้วอันต่อไปล่ะ?

sasha

การแจ้งเตือนสปอยเลอร์ด้านล่างเป็นรูปแบบแคชค่อนข้างชัดเจน

มันขึ้นอยู่กับเงื่อนไขเพิ่มเติมเช่นตัวเลขที่ไม่เปลี่ยนแปลงในการทำงานผมจะเรียกมันเปลี่ยนเริ่มต้นจำนวนเงินที่เป็นจุดเริ่มต้น

การบางอย่างโดยพลการวิ่งเช่นและการเริ่มต้นจาก0ไป9เราสามารถแคชรูปแบบทุกจากจุดเริ่มต้นถึง100นับจำนวนขององค์ประกอบ (รู้วิธีที่จะจัดการกับเคาน์เตอร์ซึ่งเป็นสิ่งจำเป็นเพื่อให้บางn - ทีเอชหมายเลข) และจดจำ 10009100n-เสื้อชั่วโมง

ตกลง. จนถึงตอนนี้การเริ่มต้นใด ๆ ที่ครอบคลุมการเปลี่ยนแปลงที่เกิน ? น่าเสียดายที่รูปแบบนี้หยุดทำงานเพราะถ้าคุณลองจาก100ทำให้เริ่มต้นเท่ากับ1ตัวเลขถัดไปจะถูกคำนวณอย่างสมบูรณ์แบบ 100
1001

ที่นี่เรามีเพื่อให้ครอบคลุมการเปลี่ยนแปลงชุดและเริ่มต้นการตั้งค่าเป็น0 แต่ยังหมายถึงตารางการคำนวณที่แตกต่างกันสำหรับการเปลี่ยนแปลง 10

เราจำเป็นต้องคำนวณทั้งหมดหรือไม่? ไม่จริงไม่
ส่วนหนึ่งของตารางเป็นอีกหนึ่งรายการเริ่มต้นเพิ่มเติม
ตัวอย่างเช่นเริ่มจากให้ลำดับเดียวกันเปลี่ยน ดังนั้นเราต้องคำนวณแคชอีกต่อไปหรือไม่ ไม่เราคำนวณมันเพื่อเปลี่ยนการเปลี่ยนแปลงเพื่อรับการวิ่งอีกครั้งดังนั้นมันจะประหยัดหน่วยความจำได้มาก 1,2,4,8

11012183054065176077198059041003



100,1000,10000,100000,1000000 ...
100


4

เมื่อคุณถามหา "ทิศทางใหม่หรือคำใบ้" และฉันไม่รู้คำตอบฉันจะออกจากที่นี่ฉันหวังว่าจะเป็นประโยชน์ ความคิดบางอย่าง:

มันสมเหตุสมผลแล้วที่จะมี pattern mod 9 ตั้งแต่นั้นมา

k>1,kZ10k1พอควร9

ซึ่งคุณสามารถพิสูจน์ได้ด้วยการเหนี่ยวนำ

ซึ่งหมายความว่าตัวเลขทั้งหมดสอดคล้องกับผลรวมของหลักของพวกเขา mod 9

an=d(an)พอควร9

an=an-1+d(an-1)=2d(an-1)พอควร9

หากเรายังคงขยายการเกิดซ้ำนี้เราจะได้รับ

an=2nพอควร9

ซึ่งอธิบายถึงรูปแบบ mod 9

an=9k+2n

นี่คือบางส่วนน้อยกว่ารหัสทั่วไป:

import matplotlib.pyplot as plt
import numpy as np

#sum digits of n
def sum_digits(n):
    s = 0
    while n:
        s += n % 10
        n //= 10
    return s

#get the sequence to n digits
def calculate(n):
    retval = [1]
    for i in range(n):
        retval.append(retval[-1] + sum_digits(retval[-1]))
    return retval;

#empirically confirm that a_n = 2^n mod 9
def confirmPow2(a):
    count = 0
    for i in a[:10000]:
        if((i%9) != (2**count % 9)):
            print "false"
        count = count + 1

#find gaps divisible by 9 in a subset of a
def find9Gaps(a):
    count = 0
    S = []
    for i in a[:10000]:
         S.append(((2**count ) - i)/9)
         count = count + 1
    return S

#repeatedly sum the digits until they're less than 9...
#gives some interesting patterns
def repeatedDigitSum():
    for i in range(1000, 1100):
         print "=========for ",i
         while i > 9:
                 i = sum_digits(i)
                 print i 


a = calculate(10**6)
b = find9Gaps(a)
plt.plot(range(len(b[:100])), b[:100])
plt.show()

เนื้อเรื่อง (สำหรับ 100 ข้อแรก) ดูเป็นเลขยกกำลัง แต่ฉันไม่คิดว่ามันสมบูรณ์แบบ

พล็อตสำหรับช่องว่าง

นี่คือผลลัพธ์ของ

>>> plt.plot(range(len(b[5:60])), np.log2(np.array(b[5:60])))
>>> plt.show()

พล็อตลอการิทึมของช่องว่าง

สิ่งสุดท้ายที่ฉันมีคือดูเหมือนว่าถ้าคุณรวมตัวเลขของตัวเลขแล้วรวมจำนวนหลักของจำนวนผลลัพธ์แล้วทำซ้ำสิ่งนี้ในที่สุดคุณก็จะได้รับ mod mod 9

ทำให้รู้สึกถึงข้อเท็จจริงข้างต้นเกี่ยวกับพลังของ 10 mod 9

nd(n)d(d(n))พอควร9

มันให้ลำดับตัวเลขที่น่าสนใจ

แก้ไข: เห็นได้ชัดว่าสิ่งนี้เรียกว่า "ดิจิตอลรูท"


1
มันถูกคอมเม้นท์อย่างน้อยสามครั้ง นอกจากนี้เมื่อคุณพล็อตที่ดูเป็นเลขชี้กำลังสำหรับคุณบางทีคุณควรใช้ลอการิทึมแจ้งให้ทราบในแกนสเกล? หากคุณวางแผนอ่าน 10 ^ 16 คำฉันจะต้องประทับใจจริงๆ
Evil

มีความคิดเห็นอะไร 3 ครั้ง ผู้คนบอกว่ามี "pattern mod 9" แต่ฉันรู้สึกว่ามันไม่ชัดเจนว่าเป็นอะไร ฉันเพิ่งสำรวจและแสดงความคิดเห็นในสิ่งที่ฉันมีเนื่องจากฉันไม่คิดว่าฉันจะสามารถทำงานต่อไปได้ อีกครั้งฉันไม่มีวิธีแก้ปัญหา แต่คำถามไม่ได้ถาม
quietContest

เพิ่มพล็อตบันทึกตามข้อเสนอแนะของ EvilJS ไม่สามารถพล็อตใด ๆ ที่ใหญ่กว่าได้เนื่องจากการหยุดพักจำนวนมากและฉันไม่มีเวลาดำเนินการติดตามปัญหานี้ต่อไปเลย
quietContest
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.