009 Special Pythagorean triplet -- v2.sf 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. #!/usr/bin/ruby
  2. # Daniel "Trizen" Șuteu
  3. # Date: 09 May 2018
  4. # https://github.com/trizen
  5. # https://projecteuler.net/problem=9
  6. # Runtime: 0.387s
  7. func sum_of_two_squares_solutions(n) is cached {
  8. var prod1 = 1
  9. var prod2 = 1
  10. var prime_powers = []
  11. for p,e in (n.factor_exp) {
  12. if (p % 4 == 3) { # p = 3 (mod 4)
  13. e.is_even || return [] # power must be even
  14. prod2 *= p**(e >> 1)
  15. }
  16. elsif (p == 2) { # p = 2
  17. if (e.is_even) { # power is even
  18. prod2 *= p**(e >> 1)
  19. }
  20. else { # power is odd
  21. prod1 *= p
  22. prod2 *= p**((e - 1) >> 1)
  23. prime_powers.append([p, 1])
  24. }
  25. }
  26. else { # p = 1 (mod 4)
  27. prod1 *= p**e
  28. prime_powers.append([p, e])
  29. }
  30. }
  31. prod1 == 1 && return []
  32. prod1 == 2 && return [[prod2, prod2]]
  33. # All the solutions to the congruence: x^2 = -1 (mod prod1)
  34. var square_roots = gather {
  35. gather {
  36. for p,e in (prime_powers) {
  37. var pp = p**e
  38. var r = sqrtmod(pp-1, pp)
  39. take([[r, pp], [pp - r, pp]])
  40. }
  41. }.cartesian { |*a|
  42. take(Math.chinese(a...))
  43. }
  44. }
  45. var solutions = []
  46. for r in (square_roots) {
  47. var s = r
  48. var q = prod1
  49. while (s.sqr > prod1) {
  50. (s, q) = (q % s, s)
  51. }
  52. solutions.append([prod2 * s, prod2 * (q % s)])
  53. }
  54. for p,e in (prime_powers) {
  55. for (var i = e%2; i < e; i += 2) {
  56. var sq = p**((e - i) >> 1)
  57. var pp = p**(e - i)
  58. solutions += (
  59. __FUNC__(prod1 / pp).map { |pair|
  60. pair.map {|r| sq * prod2 * r }
  61. }
  62. )
  63. }
  64. }
  65. solutions.map {|pair| pair.sort } \
  66. .uniq_by {|pair| pair[0] } \
  67. .sort_by {|pair| pair[0] }
  68. }
  69. for n in (1..Inf) {
  70. var a = sum_of_two_squares_solutions(n**2) || next
  71. var s = a.first { .sum + n == 1000 } || next
  72. say (s.prod * n)
  73. break
  74. }