ในหลอดเลือดดำของความท้าทายจำนวนมากฉันคิดว่าสิ่งนี้อาจน่าสนใจ
ในความท้าทายนี้เราจะใช้ระบบหมายเลขสารตกค้าง (RNS) เพื่อดำเนินการบวกลบและคูณกับจำนวนเต็มขนาดใหญ่
RNS คืออะไร
RNS เป็นหนึ่งในหลาย ๆ วิธีที่ผู้คนพัฒนาขึ้นเพื่อระบุจำนวนเต็ม ในระบบนี้ตัวเลขจะถูกแทนด้วยลำดับของสิ่งตกค้าง (ซึ่งเป็นผลลัพธ์หลังจากการดำเนินการโมดูลัส (เช่นส่วนที่เหลือหลังจากการหารจำนวนเต็ม)) ในระบบนี้จำนวนเต็มแต่ละตัวมีการแทนจำนวนมาก เพื่อให้ง่ายขึ้นเราจะ จำกัด สิ่งต่าง ๆ เพื่อให้จำนวนเต็มแต่ละค่ามีค่าไม่ซ้ำกัน ฉันคิดว่าการอธิบายสิ่งที่เกิดขึ้นกับตัวอย่างที่เป็นรูปธรรมนั้นง่ายกว่า
ให้เราดูที่แรกสามตัวเลขที่สำคัญ: 2, 3, 5 ในระบบอาร์เอ็นเอเราสามารถใช้ทั้งสามตัวเลขที่จะไม่ซ้ำกันแทนจำนวนที่น้อยกว่า 2 * 3 * 5 = 30 ใช้สารตกค้าง รับ 21:
21 มีค่าน้อยกว่า 30 ดังนั้นเราจึงสามารถใช้แทนผลลัพธ์หลังจาก modding ด้วย 2, 3 และ 5 (เช่นส่วนที่เหลือหลังจากจำนวนเต็มหารด้วย 2, 3 และ 5)
เราจะระบุ 21 ด้วยลำดับของจำนวนเต็มต่อไปนี้:
21 ~ {21 mod 2, 21 mod 3, 21 mod 5} = {1, 0, 1}
ดังนั้นในระบบ RNS ของเราแทนที่จะเป็น "21" เราจะใช้ {1,0,1}
โดยทั่วไปให้เป็นจำนวนเต็มnเราเป็นตัวแทนnเป็น { n mod 2, ... , n mod p_k } ที่p_kเป็นที่เล็กที่สุดที่สำคัญเช่นที่nมีค่าน้อยกว่าผลิตภัณฑ์ของช่วงเวลาทั้งหมดที่น้อยกว่าหรือเท่ากับp_k
อีกตัวอย่างหนึ่งบอกว่าเรามี 3412 เราต้องใช้ 2,3,5,7,11,13 ที่นี่เพราะ2*3*5*7*11*13=30030
ในขณะ2*3*5*7*11=2310
ที่ซึ่งมีขนาดเล็กเกินไป
3412 ~ {3412 mod 2, 3412 mod 3, 3412, mod 5, ... , 3412 mod 13} = {0, 1, 2, 3, 2, 6}
คุณสังเกตเห็นว่าการใช้ระบบนี้เราสามารถแสดงจำนวนมากค่อนข้างเจ็บปวด การใช้เศษซาก {1, 2, 3, 4, 5, 6, 7, 8, ... } เราสามารถแทนตัวเลขได้ถึง {2, 6, 30, 210, 2310, 30030, 510510, 9699690 ... } ตามลำดับ ( นี่คือซีรีส์ )
หน้าที่ของเรา
เราจะใช้สิ่งตกค้างเหล่านี้เพื่อแสดง +, -, และ * เป็นจำนวนมาก ฉันจะอธิบายกระบวนการเหล่านี้ด้านล่าง ตอนนี้ที่นี่มีรายละเอียดของอินพุตและเอาต์พุต
อินพุต
คุณจะได้รับหมายเลขสอง (อาจใหญ่มาก) ผ่านทาง stdin หรืออาร์กิวเมนต์ของฟังก์ชัน พวกเขาจะได้รับเป็นสตริงฐาน 10 หลัก
สำหรับวัตถุประสงค์ของการสรุปปัญหาที่เกิดขึ้นต่อไปที่เราเรียกว่าการป้อนข้อมูลเป็นครั้งแรกและครั้งที่สองn
สมมติ n> ม> = 0m
นอกจากนี้คุณยังจะได้รับ+
หรือ-
หรือ*
เพื่อแสดงให้เห็นการดำเนินการที่จะดำเนินการ
เอาท์พุต
ให้xเป็นจำนวนเต็ม เราจะใช้ [ x ] หมายถึงการเป็นตัวแทนอาร์เอ็นเอที่อธิบายข้างต้นของx
คุณกำลังจะออก [n] <operator> [m] = [result]
วิธีการดำเนินการใน RNS
การดำเนินการเหล่านี้ค่อนข้างง่าย รับตัวเลขสองตัวในรูปแบบ RNS เพื่อเพิ่มลบหรือคูณพวกเขาเพียงแค่ดำเนินการตามองค์ประกอบการดำเนินการที่ได้รับแล้วนำโมดูลัสมาใช้
กล่าวคือ
{1, 2, 3} + {1, 1, 4} = {(1 + 1) mod 2, (2 + 1) mod 3, (3 + 4) mod 5} = {0, 0, 2}
โปรดทราบว่าหากจำนวนของสารตกค้างที่ใช้เพื่อแสดงตัวเลขสองตัวที่แตกต่างกันนั้นไม่เหมือนกันเมื่อทำการดำเนินการคุณจะต้องขยายหมายเลข "ที่สั้นลง" เพื่อให้มีจำนวนของสารตกค้างเท่ากัน ตามกระบวนการเดียวกัน ดูกรณีทดสอบสำหรับตัวอย่าง
สิ่งเดียวกันจะเกิดขึ้นหากผลลัพธ์นั้นต้องการสิ่งตกค้างมากกว่าทั้งสองอินพุต จากนั้นอินพุตทั้งสองจะต้อง "ขยาย"
รายละเอียดที่สำคัญ
เราจะติดต่อกับคนจำนวนมากที่นี่ แต่จะไม่ใหญ่โดยพลการ เราจะเป็นผู้รับผิดชอบตัวเลขถึงผลิตภัณฑ์ใน 100 ช่วงแรก (ดูด้านล่าง) ด้วยเหตุนี้คุณจะได้รับ 100 ช่วงแรกฟรี (ต้นทุนไบต์) คุณอาจติดมันในอาร์เรย์ที่เรียกว่า
p
หรือสิ่งที่เป็นสำนวนภาษาของคุณแล้วลบจำนวนไบต์ที่ใช้ในการเริ่มต้นอาร์เรย์นี้จากผลรวมสุดท้ายของคุณ หลักสูตรนี้หมายความว่าพวกเขาอาจจะฮาร์ดโค้ดหรือคุณอาจใช้บิวด์อินเพื่อสร้างมันถ้าด้วยเหตุผลบางอย่างนี่เป็นการแสดงค่าจำนวนเต็มเริ่มต้นที่ใช้ในภาษาของคุณ นั่นเป็นเรื่องปกติ
คุณไม่สามารถใช้งาน Arbitrary Precision Integer ประเภทใดก็ได้เว้นแต่จะเป็นค่าเริ่มต้นของภาษาของคุณ หากเป็นค่าเริ่มต้นคุณไม่สามารถใช้เพื่อเก็บจำนวนเต็มที่โดยทั่วไปจะไม่พอดีกับ 64 บิต
เพื่อความชัดเจนเลขจำนวนเต็มแต่ละค่าจะถูกแทนด้วยจำนวนที่น้อยที่สุดที่เป็นไปได้ สิ่งนี้มีทั้งอินพุตและเอาต์พุต
ฉันคิดว่ารายละเอียดอื่น ๆ ควรป้องกันสิ่งนี้ แต่จะซ้ำซ้อน: คุณไม่สามารถทำการดำเนินการที่กำหนดในอินพุตจากนั้นเปลี่ยนทุกอย่างเป็น RNS แล้วส่งออก คุณต้องเปลี่ยนอินพุตเป็น RNS จากนั้นดำเนินการเพื่อสร้างเอาต์พุต
กรณีทดสอบ
การป้อนข้อมูล:
n = 10
m = 4
+
เอาท์พุท:
{ 0, 1, 0 } + { 0, 1 } = { 0, 2, 4 }
คำอธิบาย:
ก่อนอื่นให้เปลี่ยนแต่ละตัวเลขเป็นการแสดง RNS ตามที่อธิบายไว้ข้างต้น:
10 ~ {0,1,0}
4 ~ {0,1}
และ แจ้งให้ทราบว่าเมื่อเราต้องการที่จะทำนอกเหนือจากองค์ประกอบที่ชาญฉลาดที่มีองค์ประกอบมากกว่า10
4
ดังนั้นเราจะต้อง "ขยาย" จำนวนที่สั้นกว่านี้ 4 ~ {0,1} --> {0,1, 4 mod 5} = {0,1,4}
ดังนั้นเราจะเขียนสั้น ๆ ตอนนี้เราดำเนินการเพิ่มเติมและรับโมดูลัส
- อินพุต
n=28
m=18
+
เอาท์พุท:
[ 0, 1, 3 ] + [0, 0, 3 ] = [ 0, 1, 1, 4 ]
- อินพุต (ฉันบดหน้าของฉันบนแป้นพิมพ์)
n=1231725471982371298419823012819231982571923
m=1288488183
*
เอาท์พุท (แตกไปยังบรรทัดที่แยกต่างหากสำหรับการอ่าน)
[1, 2, 3, 6, 2, 10, 2, 1, 12, 16, 7, 15, 34, 29, 31, 5, 55, 32, 66, 61, 3, 76, 52, 14, 65, 44, 99, 57 ]
*
[1, 0, 3, 3, 4, 8, 9, 10, 8, 0 ]
=
[1, 0, 4, 4, 8, 2, 1, 10, 4, 0, 17, 7, 27, 21, 44, 51, 56, 9, 6, 9, 12, 0, 52, 36, 43, 68, 99, 24, 96, 39, 96, 66, 125]
n
ต้อง 28 ช่วงเวลา m
ต้องการ 10. n*m
ต้อง 33
- อินพุต
n=8709668761379269784034173446876636639594408083936553641753483991897255703964943107588335040121154680170867105541177741204814011615930342030904704147856733048115934632145172739949220591246493529224396454328521288726490
m=1699412683745170450115957274739962577420086093042490863793456500767137147999161679589295549397604032154933975242548831536518655879433595016
-
เอาท์พุท:
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 509]
-
[0, 2, 1, 6, 1, 12, 11, 18, 14, 28, 21, 36, 37, 42, 16, 52, 41, 60, 16, 70, 49, 78, 80, 88, 49, 100, 13, 106, 4, 112, 68, 130, 36, 138, 37, 150, 0, 162, 8, 172, 163, 180, 18, 192, 129, 198, 135, 222, 78, 228, 90, 238, 57, 250, 36, 262, 87, 270, 206, 280, 193, 292, 253, 310, 224, 316, 57, 336, 48, 348]
=
[0, 1, 4, 1, 10, 1, 6, 1, 9, 1, 10, 1, 4, 1, 31, 1, 18, 1, 51, 1, 24, 1, 3, 1, 48, 1, 90, 1, 105, 1, 59, 1, 101, 1, 112, 1, 0, 1, 159, 1, 16, 1, 173, 1, 68, 1, 76, 1, 149, 1, 143, 1, 184, 1, 221, 1, 182, 1, 71, 1, 90, 1, 54, 1, 89, 1, 274, 1, 299, 1, 266, 1, 228, 1, 340, 1, 170, 1, 107, 1, 340, 1, 88, 1, 157, 1, 143, 1, 22, 1, 22, 1, 58, 1, 296, 1, 371, 1, 140]
n
ใช้ 100 ครั้ง m
ใช้ 70 ครั้ง n-m
ใช้ 99 ครั้ง
ฉันตรวจสอบสิ่งเหล่านี้โดยใช้การChineseRem
ดำเนินการตามทฤษฎีบท Remainder ภาษาจีนในตัวบน GAP (ซึ่งโดยทั่วไปใช้หมายเลข RNS และเปลี่ยนเป็นฐาน 10 จำนวนเต็ม) ฉันเชื่อว่าพวกเขาถูกต้อง หากสิ่งที่ดูเหมือนคาวโปรดแจ้งให้เราทราบ
สำหรับผู้ที่สนใจผลิตภัณฑ์ของ 100 ครั้งแรกคือ:
471193079990618495316248783476026042202057477340967552018863483961641533584503
422120528925670554468197243910409777715799180438028421831503871944494399049257
9030720635990538452312528339864352999310398481791730017201031090
จำนวนนี้คือ 1 มากกว่าจำนวนสูงสุดที่เราสามารถแสดงได้โดยใช้ระบบที่กำหนด (และข้อ จำกัด ที่สำคัญ 100 ข้อ)
(a,b,o)=>a.map((v,i)=>eval(v+o+b[i]))
ใน ES6 เช่น ฉันคิดว่าส่วนที่ยากที่สุดคือการหาจำนวนของจำนวนที่ต้องการเพื่อแสดงผลลัพธ์โดยไม่ต้องใช้เลขคณิตความแม่นยำโดยพลการแม้ว่าการแปลงที่ตามมาเป็น RNS นั้นไม่ใช่เรื่องเล็กน้อย
1234,1234,+
ไหม( )