795 Alternating GCD Sum.sf 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. #!/usr/bin/ruby
  2. # Author: Trizen
  3. # Date: 02 May 2022
  4. # https://github.com/trizen
  5. # Alternating GCD Sum
  6. # https://projecteuler.net/problem=795
  7. # Formula:
  8. # g(4) = 6
  9. # g(n) = -n, if n is odd
  10. # g(2^k * n) = (g2(2^k) - 2^k) * Prod_{p^e | n} g2(p^e), where n is odd
  11. # where:
  12. # g2(n) = A078430(n)
  13. # = Sum_{d|n} d * phi(n/d) * f(n/d)
  14. # where:
  15. # f(n) = A000188(n)
  16. # = Prod_{p^e | n} p^floor(e/2)
  17. # Then:
  18. # G(n) = Sum_{k=1..n} g(k)
  19. # See also:
  20. # https://oeis.org/A078430 -- Sum of gcd(k^2,n) for 1 <= k <= n.
  21. # https://oeis.org/A199084 -- Sum_{k=1..n} (-1)^(k+1) gcd(k,n).
  22. # https://oeis.org/A000188 -- Number of solutions to x^2 == 0 (mod n).
  23. # Too slow in Sidef.
  24. # See the Perl version.
  25. func f(n) {
  26. n.factor_prod {|p,e|
  27. (e == 1) ? 1 : p**(e>>1)
  28. }
  29. }
  30. func g2(n) {
  31. n.is_prime && return (n + (n-1))
  32. static cache = Hash()
  33. cache{n} := n.divisors.sum {|d|
  34. d * phi(n/d) * f(n/d)
  35. }
  36. }
  37. func g(n) {
  38. return -n if n.is_odd
  39. return 6 if (n == 4)
  40. if (is_prime(n>>1)) {
  41. return n-1
  42. }
  43. var k = n.valuation(2)
  44. n >>= k
  45. (g2(ipow2(k)) - ipow2(k)) * n.factor_prod {|p,e|
  46. g2(p**e)
  47. }
  48. }
  49. func G(n) {
  50. sum(1..n, g)
  51. }
  52. assert_eq(g(2 * 47), 93);
  53. assert_eq(g(97), -97);
  54. assert_eq(g(3 * 31), -93);
  55. assert_eq(G(100), 7111);
  56. assert_eq(G(200), 36268);
  57. assert_eq(G(300), 89075);
  58. assert_eq(G(1234), 2194708);
  59. say ":: Computing G(12345678)..."
  60. say G(12345678)