757 Stealthy Numbers.pl 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # Date: 05 June 2021
  4. # https://github.com/trizen
  5. # Stealthy Numbers
  6. # https://projecteuler.net/problem=757
  7. # These are numbers of the form x*(x+1) * y*(y+1), where x and y are positive integers.
  8. # Also known as bipronic numbers.
  9. # See also:
  10. # https://oeis.org/A072389
  11. # Runtime: ~1 hour.
  12. # See the Julia version for a faster solution.
  13. use 5.020;
  14. use strict;
  15. use warnings;
  16. use ntheory qw(:all);
  17. use experimental qw(signatures);
  18. sub get_representations($v) {
  19. my @representations;
  20. foreach my $a (divisors($v)) {
  21. my $b = divint($v, $a);
  22. last if ($b <= $a);
  23. my $s = mulint($a, $a) - vecprod(2, $a, $b) - 2 * $a + mulint($b, $b) - 2 * $b + 1;
  24. $s < 0 and next;
  25. my $d = (sqrtint($s) + $a + $b - 1);
  26. $d % 2 == 0 or next;
  27. $d >>= 1;
  28. if ($v % $d == 0) {
  29. my $c = divint($v, $d);
  30. push @representations, [$a, $b, $c, $d];
  31. }
  32. }
  33. return @representations;
  34. }
  35. use Data::Dump qw(pp);
  36. pp [get_representations(36)];
  37. pp [get_representations(570024)];
  38. my $n = powint(10, 14);
  39. my %seen;
  40. my $count = 0;
  41. my $limit = rootint($n, 4);
  42. my @range = 1 .. $limit;
  43. foreach my $x (1 .. $limit) {
  44. for (my $y = $x ; ; ++$y) {
  45. my $v = $x * ($x + 1) * $y * ($y + 1);
  46. last if ($v > $n);
  47. my $duplicate = 0;
  48. foreach my $d ((divisors($v) < $limit) ? divisors($v) : @range) {
  49. last if ($d > $limit);
  50. $v % $d == 0 or next;
  51. if ($v % ($d * ($d + 1)) == 0) {
  52. my $q = divint($v, $d * ($d + 1));
  53. my $a = (sqrtint(4 * $q + 1) - 1) >> 1;
  54. next if ($d > $a);
  55. if ($v == $d * ($d + 1) * $a * ($a + 1)) {
  56. ++$duplicate;
  57. }
  58. }
  59. }
  60. if ($duplicate > 1) {
  61. $seen{$v} = $duplicate - 1;
  62. }
  63. ++$count;
  64. }
  65. }
  66. say $count;
  67. say scalar keys %seen;
  68. say $count - vecsum(values %seen);