中国の剰余定理


21

中国剰余定理は、我々は常に異なるプライムモジュラスの下に必要な残りを生産数を見つけることができることを教えてくれる。あなたの目標は、そのような数を多項式時間で出力するコードを書くことです。最短のコードが優先されます。

たとえば、これらの制約が与えられているとしましょう(%modを表します):

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

1つのソリューションはn=44です。最初の制約が満たされているのは44 = 6*7 + 2、で44割った2ときに余りがある7ため44 % 7 == 2です。他の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=0n=1n=2、というように、あなたのコードは、多項式時間で実行する必要があります入力の長さm入力の数値にはlength Θ(log m)があるため、それm自体の長さは多項式ではないことに注意してください。つまりm、操作m時間までカウントしたり操作したりすることはできませんが、値の算術演算を計算することはできます。

これを回避するために単項式のような非効率的な入力形式を使用することはできません。

その他の禁止

次を実行するためのビルトインは許可されていません。中国剰余定理の実装、方程式の解、または因子数。

組み込みを使用してmodを見つけ、モジュラー加算、減算、乗算、および指数(自然数指数を使用)を実行できます。モジュラー逆行列、除算、順序検索など、他の組み込みのモジュラー操作を使用することはできません

テストケース

これらは、最小の非負のソリューションを提供します。あなたの答えは異なる場合があります。出力が各制約を満たしていることを直接確認する方が良いでしょう。

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

@flawr:そう思う。
アレックスA.

@xnor:あなたはどう思いますか?最適化機能はどうですか?
flawr

回答:


9

Mathematica、55 51 45

モジュラー逆行列は禁止されていますが、モジュラーべき乗は許可されています。フェルマーの小定理することにより、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
あなたが使用できるように、最も内側の関数の引数の順序を入れ替えることにより、1つのバイトを保存することができますPowerMod[#2,#-2,#]し、私も48にそれをダウンさせ、名前を付けることにする機能のための要件がないと思う
マーティン・エンダー

はい、名前のない関数は問題ありません。
XNOR

6

Python 2、 165 101 99 98 85バイト

他の答えのようにフェルマーの小さな定理を使用します。最小のソリューションには関心がないので、最終的な合計をモジュラー範囲内に維持することに煩わされません。13バイトを節約してくれた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
前にスペースを削除できforます。
isaacg

1
x/a*b*pow(x/a,a-2,a)for a,b in l動作するはずです。
ボラティリティ

素晴らしい点!私はそこにある明白な冗長性を取り除こうとしていましたが、ただ開梱できることを忘れていました。
ウリグランタ

4

ピス、40 37 36 29

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

alephalphaのおかげで、Fermatの小さな定理を使用します。この式を使用し計算します。


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)

あなたは、呼び出し時に括弧を必要としないrequireevalまたはputs
タトルマン

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、68100バイト

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

編集:高速な「電源/ 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の実装は、指数がmodの前に膨大な数を生成するため、多項式時間ではないと思われます。最後のテストケースを試しましたか?
XNOR

@xnor:私の2GBマシンでは、数秒後に最後のテストケースのメモリが不足します。高速電源/ MOD機能を追加しました。
-nimi
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.