381 prime-k factorial.pl 1.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. #!/usr/bin/perl
  2. # Author: Daniel "Trizen" Șuteu
  3. # License: GPLv3
  4. # Date: 21 August 2016
  5. # Website: https://github.com/trizen
  6. # https://projecteuler.net/problem=381
  7. # Runtime: 7.220s
  8. # Based on the following relations:
  9. #
  10. # (p-1)! mod p = p-1
  11. # (p-2)! mod p = 1
  12. # (p-3)! mod p = (p-1)/2
  13. #
  14. # (p-4)! mod p has two paths:
  15. #
  16. # If (p+1) is divisible by 6, then: (p-4)! mod p = (p+1)/6
  17. # If (p+1) is not divisible by 6, then: (p-4)! mod p = p-floor(p/6)
  18. #
  19. # (p-5)! mod p has about 7 paths, which only two I analyzed:
  20. #
  21. # If (p-1) is divisible by 24, then (p-5)! mod p = (p-1)/24
  22. # If (p+1) is divisible by 24, then (p-5)! mod p = p - (p+1)/24
  23. #
  24. # In all other cases of (p-5)! mod p, it uses a specialized algorithm for computing factorial(p-5) mod p.
  25. use 5.010;
  26. use strict;
  27. use integer;
  28. use ntheory qw(forprimes invmod);
  29. sub facmod {
  30. my ($n, $mod) = @_;
  31. my $f = 1;
  32. foreach my $k ($n + 1 .. $mod - 1) {
  33. $f *= $k;
  34. $f %= $mod;
  35. }
  36. (-1 * invmod($f, $mod) + $mod) % $mod
  37. }
  38. sub S {
  39. my ($p) = @_;
  40. ( 1
  41. + ($p - 1)
  42. + (($p - 1) / 2)
  43. + (($p + 1) % 6 == 0 ? ($p + 1) / 6 : $p - ($p / 6))
  44. + (($p - 1) % 24 == 0 ? ($p - 1) / 24
  45. : ($p + 1) % 24 == 0 ? ($p - (($p + 1) / 24))
  46. : facmod($p - 5, $p)
  47. )
  48. ) % $p;
  49. }
  50. my $sum = 0;
  51. forprimes { $sum += S($_) } 5, 10**8;
  52. say $sum;