694 Cube-full Divisors.pl 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # Date: 10 February 2020
  4. # https://github.com/trizen
  5. # See also:
  6. # https://oeis.org/A036966
  7. # THE DISTRIBUTION OF CUBE-FULL NUMBERS, by P. SHIU (1990).
  8. # https://projecteuler.net/problem=694
  9. # Runtime: 9.783s
  10. use 5.020;
  11. use integer;
  12. use warnings;
  13. use ntheory qw(:all);
  14. use experimental qw(signatures);
  15. sub bsearch_le ($left, $right, $callback) {
  16. my ($mid, $cmp);
  17. for (; ;) {
  18. $mid = ($left + $right) >> 1;
  19. $cmp = $callback->($mid) || return $mid;
  20. if ($cmp < 0) {
  21. $left = $mid + 1;
  22. $left > $right and last;
  23. }
  24. else {
  25. $right = $mid - 1;
  26. if ($left > $right) {
  27. $mid -= 1;
  28. last;
  29. }
  30. }
  31. }
  32. return $mid;
  33. }
  34. sub powerful_numbers ($n, $k) { # k-powerful numbers <= n
  35. my @powerful;
  36. sub ($m, $r) {
  37. if ($r < $k) {
  38. push @powerful, $m;
  39. return;
  40. }
  41. for my $v (1 .. rootint(divint($n, $m), $r)) {
  42. if ($r > $k) {
  43. gcd($m, $v) == 1 or next;
  44. is_square_free($v) or next;
  45. }
  46. __SUB__->($m * powint($v, $r), $r - 1);
  47. }
  48. }->(1, 2 * $k - 1);
  49. sort { $a <=> $b } @powerful;
  50. }
  51. sub sum_of_cubefull_divisors_count($n) {
  52. my $t = 0;
  53. my $s = sqrtint($n);
  54. my @sqrt_cubefull = powerful_numbers($s, 3);
  55. foreach my $k (@sqrt_cubefull) {
  56. $t += $n / $k;
  57. }
  58. my @cubefull = powerful_numbers($n, 3);
  59. for (my $k = 1 ; $k <= $s ; ++$k) {
  60. my $w = $n / $k;
  61. my $i = bsearch_le(0, $#cubefull,
  62. sub ($j) {
  63. $cubefull[$j] <=> $w;
  64. }
  65. );
  66. my $r = $n / $cubefull[$i];
  67. $r = $s if ($r > $s);
  68. $t += (1 + $i) * ($r - $k + 1);
  69. $k = $r;
  70. }
  71. $t -= $s * scalar(@sqrt_cubefull);
  72. return $t;
  73. }
  74. foreach my $n (1..18) {
  75. say("S(10^$n) = ", sum_of_cubefull_divisors_count(powint(10, $n)));
  76. }
  77. __END__
  78. S(10^1) = 11
  79. S(10^2) = 126
  80. S(10^3) = 1318
  81. S(10^4) = 13344
  82. S(10^5) = 133848
  83. S(10^6) = 1339485
  84. S(10^7) = 13397119
  85. S(10^8) = 133976753
  86. S(10^9) = 1339780424
  87. S(10^10) = 13397833208
  88. S(10^11) = 133978396859
  89. S(10^12) = 1339784112539
  90. S(10^13) = 13397841446161
  91. S(10^14) = 133978415161307
  92. S(10^15) = 1339784153146359
  93. S(10^16) = 13397841534812404
  94. S(10^17) = 133978415355411689