451 Modular inverses.pl 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # License: GPLv3
  4. # Date: 03 October 2017
  5. # https://github.com/trizen
  6. # https://projecteuler.net/problem=451
  7. # Runtime: ~5 minutes
  8. use 5.010;
  9. use strict;
  10. use warnings;
  11. use ntheory qw(:all);
  12. sub l {
  13. my ($n) = @_;
  14. # Power of two (n > 4)
  15. if (not($n & ($n - 1)) and $n > 4) {
  16. return (($n >> 1) + 1);
  17. }
  18. # n+1 is a square, therefore l(n) = n - sqrt(n+1)
  19. if (is_square($n+1)) {
  20. return ($n - sqrtint($n+1));
  21. }
  22. # Prime power or twice a prime power
  23. if (is_prime_power($n) or ($n % 2 == 0 and is_prime_power($n >> 1))) {
  24. return 1;
  25. }
  26. my %table;
  27. foreach my $f (factor_exp($n)) {
  28. my $pp = $f->[0]**$f->[1];
  29. if ($pp == 2) {
  30. push(@{$table{$pp}}, [1, $pp]);
  31. }
  32. elsif ($pp == 4) {
  33. push(@{$table{$pp}}, [1, $pp], [3, $pp]);
  34. }
  35. elsif ($pp % 2 == 0) { # 2^k, where k >= 3
  36. push(@{$table{$pp}},
  37. [$pp / 2 - 1, $pp], [$pp - 1, $pp],
  38. [$pp / 2 + 1, $pp], [$pp + 1, $pp]);
  39. }
  40. else { # odd prime power
  41. push(@{$table{$pp}}, [1, $pp], [$pp - 1, $pp]);
  42. }
  43. }
  44. my $solution = 1;
  45. # Generate the solutions and pick the largest one bellow n-1
  46. forsetproduct {
  47. my $x = chinese(@_);
  48. if ($x > $solution and $x < $n - 1) {
  49. $solution = $x;
  50. }
  51. } values %table;
  52. return $solution;
  53. }
  54. my $sum = 0;
  55. foreach my $d (3 .. 2e7) {
  56. $sum += l($d);
  57. }
  58. say $sum;