Çok sayıdaki zorluğun damarı içerisinde bunun ilginç olabileceğini düşündüm.
Bu zorlukta, büyük tamsayılarda toplama, çıkarma ve çarpma işlemleri yapmak için Artık Sayı Sistemini (RNS) kullanacağız.
RNS nedir
RNS, insanların tam sayıları tanımlamak için geliştirdikleri birçok yoldan biridir. Bu sistemde, sayılar bir kalıntı dizisi ile temsil edilir (ki bu bir modül işleminden sonraki sonuçlardır (yani, tamsayı bölünmesinden sonra kalan)). Bu sistemde, her bir tamsayı birçok gösterime sahiptir. Her şeyi basit tutmak için, her bir tamsayı benzersiz bir şekilde temsil edilmek üzere işleri sınırlayacağız. Somut bir örnekle neler olduğunu anlatmanın daha kolay olduğunu düşünüyorum.
İlk üç asal sayıya bakalım: 2, 3, 5. RNS sisteminde, bu üç sayıyı, artıkları kullanarak 2 * 3 * 5 = 30'dan küçük herhangi bir sayıyı benzersiz şekilde göstermek için kullanabiliriz . 21'i al.
21, 30'dan küçüktür, bu yüzden 2, 3 ve 5 ile modlama sonrası sonuçları kullanarak temsil edebiliriz (yani, tamsayıdan sonra 2, 3 ve 5'e bölerek kalanı)
21'i aşağıdaki tamsayılar dizisiyle tanımlayacağız:
21 ~ {21 mod 2, 21 mod 3, 21 mod 5} = {1, 0, 1}
Ve böylece RNS sistemimizde "21" yerine {1,0,1} kullanırdık.
Genelde n bir tamsayı verilirse , n'yi { n mod 2, ..., n mod p_k } olarak temsil ederiz , burada p_k en küçük asaldır, öyle ki n , p p'den küçük veya eşit olan tüm primerlerin ürününden daha azdır .
Başka bir örnek, biz 3412. söylüyorlar nedeniyle burada 2,3,5,7,11,13 kullanmak gerekmez 2*3*5*7*11*13=30030
, oysa 2*3*5*7*11=2310
çok küçük olduğu.
3412 ~ {3412 mod 2, 3412 mod 3, 3412, mod 5, ..., 3412 mod 13} = {0, 1, 2, 3, 2, 6}
Bu sistemi kullanarak çok büyük sayıları nispeten acısız bir şekilde temsil edebileceğimizi fark ediyorsunuz. {1, 2, 3, 4, 5, 6, 7, 8, ...} kalıntılarını kullanarak, {2, 6, 30, 210, 2310, 30030, 510510, 9699690 ...} 'e kadar sayıları temsil edebiliriz. sırasıyla. ( İşte dizi )
Görevimiz
Bu kalıntıları çok sayıda üzerinde +, - ve * yapmak için kullanacağız. Bu süreçleri aşağıda tarif edeceğim. Şimdilik burada giriş ve çıkış bilgileri verilmiştir.
Giriş
Bir stdin veya işlev argümanı ile size iki (potansiyel olarak çok büyük) sayı verilir. 10 basamak baz dizileri olarak verilecektir.
Ayrıca aksaklıkları belirten amaçları doğrultusunda, ilk girişi diyoruz n
ve ikinci m
. Varsayalım n> m> = 0 .
Ayrıca verilecek +
ya -
ya *
gerçekleştirmek için operasyon belirtmek için.
Çıktı
Let x bir tamsayı. Yukarıda x'in yukarıda açıklanan RNS temsiline atıfta bulunmak için [ x ] kullanacağız .
Çıkacaksın [n] <operator> [m] = [result]
RNS'de işlemler nasıl gerçekleştirilir
Bu işlemler nispeten basittir. RNS notasyonunda iki sayı verilmişse, toplama, çıkarma veya çarpma işlemlerinde, verilen işlemleri tek tek uygulayın ve ardından modülü alın.
yani
{1, 2, 3} + {1, 1, 4} = {(1 + 1) mod 2, (2 + 1) mod 3, (3 + 4) mod 5} = {0, 0, 2}
İki farklı sayıyı temsil etmek için kullanılan kalıntıların sayısı aynı değilse, işlemler gerçekleştirilirken, aynı sayıda kalıntıya sahip olması için "daha kısa" sayıyı uzatmanız gerekeceğini unutmayın. Bu aynı işlemi takip eder. Örnek için test durumlarına bakın.
Aynı sonuç, her iki girişten daha fazla artık gerektiriyorsa geçerlidir. Ardından her iki girişin de "uzatılması" gerekir.
Önemli Detaylar
Burada büyük sayılarla uğraşacağız, fakat keyfi olarak büyük değil. İlk 100 astarın ürün sayısına kadar olan rakamlardan biz sorumlu olacağız (aşağıya bakınız). Bu amaçla, ilk 100 astarı ücretsiz olarak (bayt ücreti yok) verilir . Bunları,
p
kendi dilinize deyimsel olarak adlandırılmış bir diziye ya da aptalca bir şeye yapıştırabilir ve daha sonra bu diziyi başlatmak için kullanılan bayt sayısını son toplamınızdan çıkarabilirsiniz. Elbette bu, kodlanmış olmaları veya bunları oluşturmak için yerleşik kullanmaları anlamına gelir.Birisi için bu, dilinizde kullanılan varsayılan tamsayı gösterimidir. Bu iyi.
Dilinizin varsayılanı olmadığı sürece herhangi bir Rasgele Hassas Tamsayı türü kullanamazsınız. Varsayılan ise, 64 bit'e sığmayan tam sayıları depolamak için kullanamazsınız.
Açık olmak gerekirse, her bir tam sayı her zaman mümkün olan en az kalıntı ile temsil edilecektir. Bu hem giriş hem de çıkış için geçerlidir.
Diğer özelliklerin bunu engellemesi gerektiğini düşünüyorum, ancak fazlalık olması gerekmiyor: Girdilerde verilen işlemi yapamayabilir ve ardından her şeyi RNS ve sonra çıktı olarak değiştirebilirsiniz. Girişleri RNS olarak değiştirmeli ve ardından çıkışı üretmek için işlemleri yapmalısınız.
Test Kılıfları
Giriş:
n = 10
m = 4
+
Çıktı:
{ 0, 1, 0 } + { 0, 1 } = { 0, 2, 4 }
Açıklama:
İlk olarak, her sayıyı yukarıda açıklandığı gibi RNS gösterimi ile değiştirin:
10 ~ {0,1,0}
ve 4 ~ {0,1}
. Bileşen düzeyinde ekleme yapmak istediğimizde, bundan 10
daha fazla bileşene sahip olduğuna dikkat edin 4
. Bu nedenle kısa sayıyı "uzatmak" zorundayız. Böylece kısaca yazacağız 4 ~ {0,1} --> {0,1, 4 mod 5} = {0,1,4}
. Şimdi eklemeye devam ediyoruz ve sonra modülü alıyoruz.
- Giriş
n=28
m=18
+
Çıktı:
[ 0, 1, 3 ] + [0, 0, 3 ] = [ 0, 1, 1, 4 ]
- Giriş (klavyede yüzümü karıştırıyorum)
n=1231725471982371298419823012819231982571923
m=1288488183
*
Çıktı (okunabilirlik için ayrı satırlara bölünür):
[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 astar gerektirir. m
10. n*m
gerektirir 33 gerektirir.
- Giriş
n=8709668761379269784034173446876636639594408083936553641753483991897255703964943107588335040121154680170867105541177741204814011615930342030904704147856733048115934632145172739949220591246493529224396454328521288726490
m=1699412683745170450115957274739962577420086093042490863793456500767137147999161679589295549397604032154933975242548831536518655879433595016
-
Çıktı:
[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 astar kullanır. m
70 astar kullanır. n-m
99 astar kullanır.
Bunları ChineseRem
, GAP üzerine Çin Kalan Teoreminin yerleşik uygulamasını kullanarak kontrol ettim (temelde RNS sayılarını alır ve bunları 10 tamsayıya dönüştürür). Doğru olduklarına inanıyorum. Bir şey balık gibi görünüyorsa, lütfen bana bildirin.
Önemseyenler için ilk 100 astarın ürünü:
471193079990618495316248783476026042202057477340967552018863483961641533584503
422120528925670554468197243910409777715799180438028421831503871944494399049257
9030720635990538452312528339864352999310398481791730017201031090
Bu sayı, verilen sistemi kullanarak temsil edebileceğimiz maksimum sayıdan 1'dir (ve 100 asal sınırlama).
(a,b,o)=>a.map((v,i)=>eval(v+o+b[i]))
işlemin yapılması örneğin ES6'da. Bence en zor kısım, rasgele hassas aritmetik kullanmadan sonucu temsil etmek için gereken primerlerin sayısını bulmak olduğunu düşünüyorum.
1234,1234,+
)?