n
大きなとの 142857 を法とする二項係数を計算する方法r
。142857 について何か特別なことはありますか? 問題がモジュロp
でどこp
が素数であるかということであれば、ルーカスの定理を使用できますが、142857 に対してはどうすればよいでしょうか。
3 に答える
実際には任意C(n,k) % m
の時間で計算できます。O(n)
m
トリックは、 を計算しn!
、素数べき乗ベクトルとして、最初の 2 つから後で 2 つを引き、余りを を法として掛けることです。これを行うため:k!
(n-k)!
m
C(10, 4)
10! = 2^8 * 3^4 * 5^2 * 7^1
4! = 2^3 * 3^1
6! = 2^4 * 3^2 * 5^1
したがって
C(10,4) = 2^1 * 3^1 * 5^1 * 7^1
mod m
割り算がないので簡単に計算できます。コツは、 と の分解をn!
線形時間で計算することです。までの素数を事前計算するとn
、次のように効率的に行うことができ1*2*...*9*10
ます2
。4 番目の数字ごとに、2 番目の数字を取得します。したがって、2
要素の数はn!
です(床材はn/2 + n/4 + n/8 + ...
どこですか)。/
残りの素数についても同じことを行います。O(n/logn)
未満の素数があり、それぞれに対して作業n
を行うO(logn)
ため、分解は線形です。
実際には、次のようにより暗黙的にコーディングします。
func Binom(n, k, mod int) int {
coef := 1
sieve := make([]bool, n+1)
for p := 2; p <= n; p++ {
// If p is not sieved yet, it is a prime number
if !sieve[p] {
// Sieve of Eratosthenes
for i := p*p; i <= n; i += p {
sieve[i] = true
}
// Calculate influence of p on coef
for pow := p; pow <= n; pow *= p {
cnt := n/pow - k/pow - (n-k)/pow
for j := 0; j < cnt; j++ {
coef *= p
coef %= mod
}
}
}
}
return coef
}
これにはエラトステネスのふるいが含まれているため、実行時間は、素数が事前に計算されているか、より高速なふるいでふるいにかけられている場合nloglogn
よりも長くなります。n
アルゴリズムは次のとおりです。
- 基数を素数べき乗に因数分解します。142857 = 3^3×11×13×37
- 各素数ベキを法として結果を計算する
- 中国剰余定理を使用して結果を結合します。
を計算するには(n above k) mod p^q
:
出典: http://www.dms.umontreal.ca/~andrew/PDF/BinCoeff.pdf、定理 1
で割り切れない(n!)_p
数の積として定義する1..n
p
基数の最下位桁を消去n_j
した後に定義するn
j
p
次のように定義r
しますn
-k
e_j
を加算するときのキャリーの数として定義し、最下位桁k+r
からのキャリーをカウントせず、基数で計算しますj
p
s
あたかもそうでない1
かのように定義するp=2 & q>=3
-1
次に(n above k) mod p^q := p^e_0 * s^e_(q-1) * concatenate(j=d..0)( (n_j!)_p / ((k_j!)_p*(r_j!)_p) )
、連結の各項で結果の基数 p の 1 桁をj
計算し、最下位でゼロ以外の最下位桁を計算します。
142857 の特別な点は、7 * 142857 = 999999 = 10^6 - 1 であるということです。これは、a=10 および p=7 のフェルマーの小定理から生じる係数であり、剰余等価 10^7 == 10 (mod 7 )。つまり、大部分はモジュロ 999999 で作業し、最後に 7 で割ることによって最終的なモジュラスに減らすことができます。この利点は、剰余除算が k=1,2,3,6 の形式 10^k の表現ベースで非常に効率的であることです。このような場合に行うことは、数字グループを一緒に追加することだけです。これは、キャスティング アウト ナインの一般化です。
この最適化は、ハードウェアの基数 10 の乗算がある場合にのみ意味があります。つまり、紙と鉛筆でこれを行う必要がある場合は、うまく機能します。この問題は最近オンライン コンテストに出たので、まさにそれが質問の起源だと思います。