248 Numbers for which Euler s totient function equals 13.pl 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # 29 September 2017
  4. # https://github.com/trizen
  5. # https://projecteuler.net/problem=248
  6. # Runtime: 0.788s
  7. use 5.010;
  8. use strict;
  9. use warnings;
  10. use ntheory qw(is_prime divisors valuation factorial);
  11. # Given a number `n`, the algorithm finds all the numbers such that for each number `k` in the list, φ(k) = n.
  12. # Based on Dana Jacobsen's code from Math::Prime::Util,
  13. # which in turn is based on invphi.gp v1.3 by Max Alekseyev.
  14. # See also:
  15. # https://en.wikipedia.org/wiki/Euler%27s_totient_function
  16. # https://github.com/danaj/Math-Prime-Util/blob/master/examples/inverse_totient.pl
  17. sub inverse_euler_phi {
  18. my ($n) = @_;
  19. my %r = (1 => [1]);
  20. foreach my $d (divisors($n)) {
  21. if (is_prime($d + 1)) {
  22. my %temp;
  23. foreach my $k (1 .. (valuation($n, $d + 1) + 1)) {
  24. my $u = $d * ($d + 1)**($k - 1);
  25. my $v = ($d + 1)**$k;
  26. foreach my $f (divisors($n / $u)) {
  27. if (exists $r{$f}) {
  28. push @{$temp{$f * $u}}, map { $v * $_ } @{$r{$f}};
  29. }
  30. }
  31. }
  32. while (my ($i, $v) = each(%temp)) {
  33. push @{$r{$i}}, @$v;
  34. }
  35. }
  36. }
  37. return if not exists $r{$n};
  38. return sort { $a <=> $b } @{$r{$n}};
  39. }
  40. say((inverse_euler_phi(factorial(13)))[150_000 - 1]);