ทฤษฏีส่วนที่เหลือของจีน


21

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

ตัวอย่างเช่นสมมติว่าเราได้รับข้อ จำกัด เหล่านี้ ( %หมายถึง mod):

n % 7  == 2
n % 5  == 4
n % 11 == 0

n=44ทางออกหนึ่งคือ ข้อ จำกัด แรกคือความพึงพอใจเพราะ44 = 6*7 + 2และเพื่อให้44มีที่เหลือ2เมื่อหารด้วยและทำให้7 44 % 7 == 2อีกสองข้อ จำกัด จะพบเช่นกัน มีอยู่แก้ปัญหาอื่น ๆ เช่นและn=814n=-341

อินพุต

รายการที่ไม่ว่างเปล่าของคู่(p_i,a_i)ซึ่งแต่ละโมดูลัสp_iเป็นสำคัญแตกต่างกันและแต่ละเป้าหมายเป็นจำนวนธรรมชาติในช่วงa_i 0 <= a_i < p_iคุณสามารถป้อนข้อมูลในแบบฟอร์มใดก็ได้ที่สะดวก ไม่จำเป็นต้องเป็นรายการคู่ คุณอาจไม่คิดว่าอินพุตถูกเรียงลำดับ

เอาท์พุต

จำนวนเต็มnเช่นว่าสำหรับแต่ละดัชนีn % p_i == a_i iไม่จำเป็นต้องมีค่าน้อยที่สุดและอาจเป็นค่าลบ

การ จำกัด เวลาพหุนาม

เพื่อป้องกันไม่ให้การแก้ปัญหาราคาถูกที่มีเพียงแค่พยายามn=0, n=1, n=2และอื่น ๆ รหัสของคุณจะต้องทำงานในเวลาพหุนามในความยาวของการป้อนข้อมูล โปรดทราบว่าตัวเลขmในอินพุตมีความยาวΘ(log m)ดังนั้นmตัวมันเองจึงไม่ใช่พหุนามในความยาว ซึ่งหมายความว่าคุณไม่สามารถนับถึงmหรือทำmเวลาดำเนินการได้แต่คุณสามารถคำนวณการดำเนินการทางคณิตศาสตร์กับค่าได้

คุณไม่สามารถใช้รูปแบบการป้อนข้อมูลที่ไม่มีประสิทธิภาพเช่นเดียวกับที่ไม่ได้รับสิ่งนี้

เรย์แบนอื่น ๆ

ไม่อนุญาตให้ใช้บิวด์อินเพื่อทำสิ่งต่อไปนี้: ใช้ทฤษฎีส่วนที่เหลือของจีน, แก้สมการหรือตัวเลขปัจจัย

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

กรณีทดสอบ

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

[(5, 3)] 
3

[(7, 2), (5, 4), (11, 0)]
44

[(5, 1), (73, 4), (59, 30), (701, 53), (139, 112)]
1770977011

[(982451653, 778102454), (452930477, 133039003)]
68121500720666070

ทำไมไม่มีการแบ่ง?
jimmy23013

@ user23013 ไม่มีการแยกส่วนเนื่องจากเป็นพื้นผกผันแบบแยกส่วน
xnor

เมทริกซ์ผกผันจะนับเป็นการแก้สมการหรือไม่
ข้อบกพร่อง

@ flawr: ฉันจะคิดอย่างนั้น
Alex A.

@xnor: คุณคิดอย่างไร แล้วฟังก์ชั่นการเพิ่มประสิทธิภาพล่ะ?
ข้อบกพร่อง

คำตอบ:


9

Mathematica, 55 51 45

Modular inverse ถูกแบน แต่อนุญาตให้ใช้การยกกำลังแบบแยกส่วนได้ โดยทฤษฎีบทเล็ก ๆ น้อย ๆ n^(-1) % p == n^(p-2) % pของแฟร์มาต์,

(PowerMod[x=1##&@@#/#,#-2,#]x).#2&@@Thread@#&

ตัวอย่าง:

In[1]:= f = (PowerMod[x=1##&@@#/#,#-2,#]x).#2&@@Thread@#&;

In[2]:= f[{{5, 3}}]

Out[2]= 3

In[3]:= f[{{7, 2}, {5, 4}, {11, 0}}]

Out[3]= 1584

In[4]:= f[{{5, 1}, {73, 4}, {59, 30}, {701, 53}, {139, 112}}]

Out[4]= 142360350966

แค่เล่น ๆ:

ChineseRemainder@@Reverse@Thread@#&

1
คุณสามารถบันทึกหนึ่งไบต์โดยการสลับลำดับของอาร์กิวเมนต์ของฟังก์ชันอินเนอร์สต์ที่คุณสามารถใช้ได้PowerMod[#2,#-2,#]และฉันก็ไม่คิดว่ามีความต้องการฟังก์ชั่นที่จะตั้งชื่อนำมาสู่ 48
Martin Ender

ใช่ฟังก์ชั่นที่ไม่มีชื่อก็โอเค
xnor

6

Python 2 165 101 99 98 85 ไบต์

ใช้ทฤษฎีบทเล็ก ๆ ของแฟร์มาต์เหมือนคำตอบอื่น ๆ ไม่ต้องกังวลกับการรักษาผลรวมสุดท้ายในช่วงโมดูลาร์เนื่องจากเราไม่ได้สนใจโซลูชันที่เล็กที่สุด ขอบคุณความผันผวนสำหรับการบันทึก 13 ไบต์

l=input();x=reduce(lambda a,b:a*b[0],l,1)
print sum(x/a*b*pow(x/a,a-2,a)for a,b in l)

[(5, 3)]
3
[(7, 2), (5, 4), (11, 0)]
1584
[(5, 1), (73, 4), (59, 30), (701, 53), (139, 112)]
142360350966

1
forคุณสามารถลบพื้นที่ก่อน
isaacg

1
x/a*b*pow(x/a,a-2,a)for a,b in lควรทำงาน.
ความผันผวน

จุดสุดยอด! ฉันพยายามกำจัดความซ้ำซ้อนที่ชัดเจนที่นั่น แต่ลืมไปว่าฉันสามารถแกะกล่องออกได้
Uri Granta

4

Pyth, 40 37 36 29

M*G.^G-H2Hsm*edg/u*GhHQ1hdhdQ

ใช้ทฤษฎีบทเล็ก ๆ ของแฟร์มาต์ต้องขอบคุณ alephalpha คำนวณโดยใช้สูตรนี้


3

ทับทิม, 129

ดูเหมือนว่าโซลูชันของ Ruby จะต้องใช้เวลานานกว่าเนื่องจากการยกกำลังแบบแยกส่วนไม่สามารถใช้ได้โดยไม่ต้องโหลดไลบรารี openssl และทำการแปลงเป็น OpenSSL :: BN ถึงกระนั้นสนุกเขียนมัน:

require("openssl")
z=eval(gets)
x=1
z.map{|a,b|x*=a}
s=0
z.map{|a,b|e=a.to_bn;s+=(x/a).to_bn.mod_exp(e-2,e).to_i*b*x/a}
puts(s)

คุณไม่จำเป็นต้อง parens เมื่อเรียกร้องrequire, หรือeval puts
Tutleman

2

Python 2, 61

n=P=1
for p,a in input():n+=P*(a-n)*pow(P,p-2,p);P*=p
print n

สิ่งนี้ใช้รูปแบบของการสร้างผลิตภัณฑ์ที่คำตอบอื่น ๆ ใช้

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

ดังนั้นเราก็ต้องมีการเปลี่ยนแปลงnเพื่อตอบสนองโดยการเพิ่มหลายทางขวาของn%p == a Pเราหาค่าสัมประสิทธิ์c:

(n + P*c) % p == a

นี้ต้องการให้ที่ผกผันจะได้รับการโมดูโลc = (a-n) * P^(-1) pเป็นคนอื่น ๆ P^(-1) = pow(P,p-2,p)ทราบผกผันสามารถคำนวณได้โดยทฤษฎีบทเล็กของแฟร์มาเป็น ดังนั้นc = (a-n) * pow(P,p-2,p)และเราปรับปรุงโดยnn+= P * (a-n) * pow(P,p-2,p)


1

Haskell, 68 100 bytes

f l=sum[p#(m-2)*n*p|(m,n)<-l,let a#0=1;a#n=(a#div n 2)^2*a^mod n 2`mod`m;p=product(map fst l)`div`m]

การใช้งาน: ->f [(5,1), (73,4), (59,30), (701,53), (139,112)]142360350966

แก้ไข: ตอนนี้ด้วยฟังก์ชั่น "power / mod" ที่รวดเร็ว รุ่นเก่า (68 ไบต์) พร้อมฟังก์ชันพลังงานภายใน:

f l=sum[l#m^(m-2)`mod`m*n*l#m|(m,n)<-l]
l#m=product(map fst l)`div`m

ฉันสงสัยว่าการติดตั้ง power-mod ของคุณไม่ได้เป็นพหุนามเนื่องจากว่าเลขชี้กำลังเป็นจำนวนมากก่อนที่จะทำการดัดแปลง คุณลองกรณีทดสอบครั้งสุดท้ายแล้วหรือยัง
xnor

@xnor: กรณีทดสอบล่าสุดหมดหน่วยความจำหลังจากไม่กี่วินาทีในเครื่อง 2GB ของฉัน ฉันได้เพิ่มฟังก์ชั่น power / mod ที่รวดเร็ว
nimi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.