lucas_theorem.sf 1.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. #!/usr/bin/ruby
  2. # Daniel "Trizen" Șuteu
  3. # Date 19 September 2020
  4. # https://github.com/trizen
  5. # Simple implementation of Lucas's theorem, for computing binomial(n,k) mod p, for some prime p.
  6. # See also:
  7. # https://en.wikipedia.org/wiki/Lucas%27s_theorem
  8. func factorial_valuation (n,p) {
  9. (n - n.digits_sum(p)) / (p-1)
  10. }
  11. func modular_binomial (n, k, m) {
  12. var j = n-k
  13. var prod = 1
  14. n.each_prime { |q|
  15. var p = factorial_valuation(n, q)
  16. if (q <= k) {
  17. p -= factorial_valuation(k, q)
  18. }
  19. if (q <= j) {
  20. p -= factorial_valuation(j, q)
  21. }
  22. if (p > 0) {
  23. prod = mulmod(prod, powmod(q, p, m), m)
  24. }
  25. }
  26. return prod
  27. }
  28. func lucas_theorem (n, k, p) {
  29. return 0 if (n < k)
  30. var Nd = n.digits(p)
  31. var Kd = k.digits(p)
  32. var prod = 1
  33. [Nd, Kd].zip {|Nr, Kr|
  34. if (Nr < Kr) {
  35. return 0
  36. }
  37. prod = mulmod(prod, modular_binomial(Nr, Kr, p), p)
  38. }
  39. return prod
  40. }
  41. say lucas_theorem(1e10, 1e5, 1009) #=> 559
  42. say lucas_theorem(1e18, 1e9, 2957) #=> 2049