-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlucas_theorem.sf
60 lines (42 loc) · 1.09 KB
/
lucas_theorem.sf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#!/usr/bin/ruby
# Daniel "Trizen" Șuteu
# Date 19 September 2020
# https://github.com/trizen
# Simple implementation of Lucas's theorem, for computing binomial(n,k) mod p, for some prime p.
# See also:
# https://en.wikipedia.org/wiki/Lucas%27s_theorem
func factorial_valuation (n,p) {
(n - n.digits_sum(p)) / (p-1)
}
func modular_binomial (n, k, m) {
var j = n-k
var prod = 1
n.each_prime { |q|
var p = factorial_valuation(n, q)
if (q <= k) {
p -= factorial_valuation(k, q)
}
if (q <= j) {
p -= factorial_valuation(j, q)
}
if (p > 0) {
prod = mulmod(prod, powmod(q, p, m), m)
}
}
return prod
}
func lucas_theorem (n, k, p) {
return 0 if (n < k)
var Nd = n.digits(p)
var Kd = k.digits(p)
var prod = 1
[Nd, Kd].zip {|Nr, Kr|
if (Nr < Kr) {
return 0
}
prod = mulmod(prod, modular_binomial(Nr, Kr, p), p)
}
return prod
}
say lucas_theorem(1e10, 1e5, 1009) #=> 559
say lucas_theorem(1e18, 1e9, 2957) #=> 2049