Çin Kalan Teoremi


21

Çin Kalan Teoremi her zaman farklı asal modüllerinin altında herhangi bir istenen kalanlar üreten bir dizi bulabilirsiniz söyler. Amacınız polinom zaman içinde böyle bir sayı çıktısı almak için kod yazmak. En kısa kod kazanır.

Örneğin, bize bu kısıtlamaları verdiğimizi söyleyin ( %mod'u temsil eder):

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

Bir çözüm var n=44. Birinci kısıtlama nedeniyle tatmin edilir 44 = 6*7 + 2ve böylece 44geri kalan sahip 2bölündüğü zaman7 bu şekilde, ve 44 % 7 == 2. Diğer iki kısıtlama da yerine getirildi. Gibi diğer çözümler vardır mevcuttur n=814ve n=-341.

Giriş

(p_i,a_i)Her modülün boş olmayan bir çift listesip_i ayrı bir asal olduğu ve her hedefin a_iaralıktaki doğal bir sayı0 <= a_i < p_i . Hangi formda olursa olsun girdi alabilirsiniz; aslında çiftlerin bir listesi olmak zorunda değildir. Girişin sıralandığını varsaymayabilirsiniz.

Çıktı

nÖyle bir tam sayın % p_i == a_iHer indeks içini . Bu en küçük değer olmak zorunda değildir ve negatif olabilir.

Polinom zaman kısıtlaması

Sadece deneme ucuz çözümler önlemek için n=0, n=1, n=2ve benzeri, kodunuz içinde polinom sürede çalışmalıdır girdi uzunluğu . Girişteki bir sayının muzunluğuna sahip olduğunu Θ(log m), bu nedenle mkendisinin uzunluğunda polinom olmadığını unutmayın. Bu sayede mişlem yapamazsınız veya işlem yapamazsınızm sürelerine saymadığınız , ancak değerler üzerindeki aritmetik işlemleri hesaplayabileceğiniz .

Bunu çözmek için unary gibi verimsiz bir giriş formatı kullanamazsınız.

Diğer yasaklar

Aşağıdakileri yapmak için yerleşik yapılara izin verilmez: Çince Kalan Teoremini uygulayın, denklemleri çözün veya faktör numaralarını uygulayın.

Modları bulmak ve modüler toplama, çıkarma, çarpma ve üstelleştirme yapmak için yerleşik bileşenleri kullanabilirsiniz (doğal sayı üsteli ile). Sen olmayabilir diğer kullanmak yerleşik modüler ters, bölünme ve sipariş-bulgu dahil modüler operasyonları,.

Test durumları

Bunlar en küçük negatif olmayan çözümü veriyor. Cevabınız farklı olabilir. Çıktınızın her kısıtlamayı karşılayıp karşılamadığını doğrudan kontrol etmeniz daha iyi olur.

[(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

Neden bölünme yok?
jimmy23013

@ user23013 Modüler bir bölüm yok, çünkü temelde modüler bir ters.
XNOR

Matris inversiyonu denklemleri çözüyor mu?
kusur,

@flawr: Ben de öyle düşünürdüm.
Alex A.

@xnor: Ne düşünüyorsun? Peki ya optimizasyon fonksiyonları?
kusur,

Yanıtlar:


9

Mathematica, 55 51 45

Modüler ters yasaktır, ancak modüler üstelleştirmeye izin verilir. Fermat'ın küçük teoremi ile n^(-1) % p == n^(p-2) % p.

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

Örnek:

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

Sadece eğlence için:

ChineseRemainder@@Reverse@Thread@#&

1
Böyle kendinizin kullanabileceği en içteki fonksiyonunun argümanlar, sırasını değiştirerek bir bayt kaydedebilir PowerMod[#2,#-2,#]ve ayrıca fonksiyon için bir gereklilik 48'e için aşağı getirerek, ismini vermek var sanmıyorum
Martin Ender

Evet, adlandırılmamış işlevler tamam.
Xnor

6

Python 2, 165 101 99 98 85 bayt

Fermat'ın küçük teoremini diğer cevaplar gibi kullanmak. Son toplamı modüler aralıkta tutmakla uğraşmaz, çünkü en küçük çözümle ilgilenmiyoruz. 13 byte tasarruf için teşekkürler Volatility.

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
Önce boşluğu kaldırabilirsiniz for.
isaacg,

1
x/a*b*pow(x/a,a-2,a)for a,b in lçalışmalı.
Oynaklık

Mükemmel nokta! Oradaki bariz fazlalıktan kurtulmaya çalışıyordum ama sadece açabileceğimi unuttum.
Uri Granta

4

Pyth, 40 37 36 29

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

Halep sayesinde Fermat'ın küçük teoremini kullanır. Bu formülü kullanarak hesaplar .


3

Ruby, 129

Evet, yoldaşlar, Ruby çözümlerinin daha uzun olması gerekiyor, çünkü modüler üstelik openssl kitaplığı yüklenmeden ve OpenSSL :: BN'ye dönüşüm yapmadan kullanılamıyor. Yine de yazarken eğlendim:

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)

Sen çağrılırken parens gerekmez require, evalya da 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

Bu , diğer cevapların kullandığı ürün yapısının bir çeşitlemesini kullanır.

Fikir, nkısıtlamaları aşmak ve öncekilerle uğraşmadan mevcut kısıtlamayı karşılamak için çözümü güncellemektir . Bunu yapmak için, şimdiye Pkadar görülen primerlerin ürününü izliyoruz ve çok sayıda eklemenin P, önceden görülmüş herhangi bir prime etkiye sahip olmadığını gözlemledik .

Bu yüzden, sadece sağ katı ekleyerek ntatmin etmek için değişmemiz gerekiyor . Katsayı için çözüyoruz :n%p == aPc

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

Bu c = (a-n) * P^(-1), tersinin modulo alındığı yerde olmasını gerektirir p. Diğerlerinin de belirttiği gibi, tersi Fermat'ın Küçük Teoremi olarak hesaplanabilir P^(-1) = pow(P,p-2,p). Yani, c = (a-n) * pow(P,p-2,p)ve ntarafından güncellenir n+= P * (a-n) * pow(P,p-2,p).


1

Haskell, 68 100 bayt

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]

Kullanım: f [(5,1), (73,4), (59,30), (701,53), (139,112)]-> 142360350966.

Düzenleme: şimdi hızlı bir "güç / mod" fonksiyonu ile. Dahili güç fonksiyonlu eski versiyon (68 bytes):

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

Üslü mod önce büyük bir sayı ürettiğinden, güç-mod uygulamanızın polinom-zaman olmadığından şüpheleniyorum. Son test olayını denedin mi?
Xnor

@ xnor: son test davası 2GB makinemde birkaç saniye sonra hafızada kalıyor. Hızlı bir güç / mod işlevi ekledim.
nimi
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.