modular_binomial.pl 925 B

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
  1. #!/usr/bin/perl
  2. # Author: Daniel "Trizen" Șuteu
  3. # License: GPLv3
  4. # Date: 08 February 2017
  5. # Website: https://github.com/trizen
  6. # Algorithm for binomial(n, k) mod m.
  7. use 5.020;
  8. use strict;
  9. use warnings;
  10. use experimental qw(signatures);
  11. use ntheory qw(forprimes powmod vecsum todigits);
  12. sub factorial_power ($n, $p) {
  13. ($n - vecsum(todigits($n, $p))) / ($p - 1);
  14. }
  15. sub modular_binomial ($n, $k, $m) {
  16. my $j = $n - $k;
  17. my $prod = 1;
  18. forprimes {
  19. my $p = factorial_power($n, $_);
  20. if ($_ <= $k) {
  21. $p -= factorial_power($k, $_);
  22. }
  23. if ($_ <= $j) {
  24. $p -= factorial_power($j, $_);
  25. }
  26. if ($p > 0) {
  27. $prod *= ($p == 1) ? ($_ % $m) : powmod($_, $p, $m);
  28. $prod %= $m;
  29. }
  30. } $n;
  31. return $prod;
  32. }
  33. say modular_binomial(100, 50, 139); #=> 71
  34. say modular_binomial(124, 42, 1234567); #=> 395154