401 Sum of squares of divisors.pl 1.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # Date: 20 August 2017
  4. # Edit: 16 September 2019
  5. # https://github.com/trizen
  6. # https://projecteuler.net/problem=401
  7. # Generalized aglorithm described at:
  8. # https://trizenx.blogspot.com/2018/11/partial-sums-of-arithmetical-functions.html
  9. # Runtime: ~47 seconds.
  10. use 5.010;
  11. use strict;
  12. use integer;
  13. use warnings;
  14. use experimental qw(signatures);
  15. use ntheory qw(sqrtint mulmod divmod addmod);
  16. my $mod = 10**9;
  17. my $lim = 10**15;
  18. sub f ($n) {
  19. divmod(mulmod(mulmod($n, $n + 1, $mod), 2 * $n + 1, $mod), 3, $mod) >> 1;
  20. }
  21. sub sum_of_sum_of_squared_divisors ($n) {
  22. my $s = sqrtint($n);
  23. my $u = int($n/($s+1));
  24. my $sum = 0;
  25. my $prev = f($n);
  26. foreach my $k (1 .. $s) {
  27. my $curr = f(int($n/($k+1)));
  28. $sum = addmod($sum, mulmod($k, $prev - $curr, $mod), $mod);
  29. $prev = $curr;
  30. }
  31. foreach my $k (1 .. $u) {
  32. $sum = addmod($sum, mulmod($k*$k, int($n/$k), $mod), $mod);
  33. }
  34. return $sum;
  35. }
  36. say sum_of_sum_of_squared_divisors($lim);