518 Prime Triples and Geometric Sequences.pl 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. #!/usr/bin/perl
  2. # Author: Trizen
  3. # Date: 11 September 2023
  4. # https://github.com/trizen
  5. # Prime Triples and Geometric Sequences
  6. # https://projecteuler.net/problem=518
  7. # Solution:
  8. # `(p+1, q+1, r+1)` must form a geometric progression and `p < q < r`.
  9. #
  10. # This means that there is a positive rational value `r` such that:
  11. # (p+1)*r = q+1
  12. # (p+1)*r^2 = r+1
  13. #
  14. # Since `r` can be rational, the denominator of the reduced fraction `r` must be a divisor of `p+1`.
  15. #
  16. # Furthermore, the denominator `j` must divide `p+1` twice, since we have, with `gcd(k,j) = 1`:
  17. # (p+1)*k/j = q+1
  18. # (p+1)*k^2/j^2 = r+1
  19. #
  20. # Therefore, we iterate over the primes p <= N, then we iterate over the square-divisors j^2 of p+1,
  21. # and for each k in the range `2 .. sqrt(n/((p+1)/j^2))` we compute:
  22. # q = (p+1)*k/j - 1
  23. # r = (p+1)*k^2/j^2 - 1
  24. # Runtime: 1 minute and 30 seconds.
  25. use 5.036;
  26. use ntheory qw(:all);
  27. sub square_divisors ($n) {
  28. my @d = (1);
  29. my @pp = grep { $_->[1] > 1 } factor_exp($n);
  30. foreach my $pp (@pp) {
  31. my ($p, $e) = @$pp;
  32. my @t;
  33. for (my $i = 2 ; $i <= $e ; $i += 2) {
  34. my $u = powint($p, $i);
  35. push @t, map { $_ * $u } @d;
  36. }
  37. push @d, @t;
  38. }
  39. return @d;
  40. }
  41. sub problem_518 ($n) {
  42. my $sum = 0;
  43. my $count = 0;
  44. forprimes {
  45. my $p = $_;
  46. foreach my $jj (square_divisors($p + 1)) {
  47. my $j = sqrtint($jj);
  48. my $d1 = divint($p + 1, $j);
  49. my $d2 = divint($d1, $j);
  50. foreach my $k (2 .. sqrtint(divint($n, $d2))) {
  51. gcd($k, $j) == 1 or next;
  52. my $q = $k * $d1;
  53. my $r = $k * $k * $d2;
  54. $p < $q or next;
  55. $q < $r or next;
  56. is_prime($q - 1) or next;
  57. is_prime($r - 1) or next;
  58. ++$count;
  59. $sum += ($p + $q + $r - 2);
  60. }
  61. }
  62. } $n;
  63. return ($count, $sum);
  64. }
  65. my ($count, $sum) = problem_518(1e8);
  66. say "Count = $count";
  67. say "Sum = $sum";
  68. __END__
  69. S(10^2) = 1035
  70. S(10^3) = 75019
  71. S(10^4) = 4225228
  72. S(10^5) = 249551109 (takes 0.1 seconds)
  73. S(10^6) = 17822459735 (takes 0.9 seconds)
  74. S(10^7) = 1316768308545 (takes 9.2 seconds)