688 Piles of Plates.sf 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. #!/usr/bin/ruby
  2. # Author: Daniel "Trizen" Șuteu
  3. # Date: 15 November 2019
  4. # https://github.com/trizen
  5. # Solution to the "Piles of Plates" problem.
  6. # https://projecteuler.net/problem=688
  7. # Let:
  8. # g(k) = k mod 2
  9. # f(k) = Sum_{d|k} g(d) = Sum_{d|k, d is odd} 1
  10. # Then:
  11. # F(n) = Sum_{k=1..n} f(k)
  12. # F(n) = Sum_{k=1..n} g(k) * floor(n/k)
  13. # S(n) = Sum_{k=1..n} F(k)
  14. # S(n) = Sum_{k=1..n} Sum_{j=1..k} f(j)
  15. # S(n) = Sum_{k=1..n} f(k) * (n - k + 1)
  16. # By splitting the last sum into two sums, we get:
  17. # S(n) = (n+1)*Sum_{k=1..n} f(k) - Sum_{k=1..n} f(k)*k
  18. # In order to compute S(10^16), we need a sub-linear formula for computing:
  19. # A(n) = Sum_{k=1..n} f(k)
  20. # B(n) = Sum_{k=1..n} k*f(k)
  21. # Then:
  22. # S(n) = (n+1)*A(n) - B(n)
  23. # OEIS sequences:
  24. # A(n) = A060831(n)
  25. # B(n) = A285900(n)
  26. # Formulas:
  27. # A(n) = Sum_{k=1..floor((n+1)/2)} floor(n/(2*k-1))
  28. # B(n) = Sum_{k=1..floor((n+1)/2)} (2*k-1)/2 * floor(n/(2*k-1)) * floor(1 + n/(2*k-1))
  29. # A(n) can be computed in sub-linear time as:
  30. # A(n) = H(n) - H(floor(n/2))
  31. # where:
  32. # H(n) = Sum_{k=1..n} floor(n/k)
  33. # H(n) = 2*Sum_{k=1..floor(sqrt(n))} floor(n/k) - floor(sqrt(n))^2
  34. # Alternatively:
  35. # A(n) = Sum_{k=1..floor(sqrt(n))} (V(floor(n/k)) + g(k)*floor(n/k)) - V(floor(sqrt(n)))*floor(sqrt(n))
  36. # where:
  37. # V(n) = floor((n+1)/2)
  38. # B(n) can be computed in sub-linear time as:
  39. # B(n) = Sum_{k=1..floor(sqrt(n))} k * (G(floor(n/k)) + g(k) * F_1(floor(n/k))) - F_1(floor(sqrt(n))) * G(floor(sqrt(n)))
  40. # where:
  41. # G(n) = floor((n+1)/2)^2
  42. # F_1(n) = n*(n+1)/2
  43. #----------------------------------
  44. func g(k) { k % 2 }
  45. #----------------------------------
  46. func f(k) {
  47. k.divisors.sum {|d| g(d) }
  48. }
  49. #----------------------------------
  50. func F1(n) {
  51. sum(1..n, {|k|
  52. f(k)
  53. })
  54. }
  55. #----------------------------------
  56. func F2(n) {
  57. sum(1..n, {|k|
  58. g(k) * floor(n/k)
  59. })
  60. }
  61. #----------------------------------
  62. func S1(n) {
  63. sum(1..n, {|k|
  64. F1(k)
  65. })
  66. }
  67. #----------------------------------
  68. func S2(n) {
  69. sum(1..n, {|k|
  70. (n - k + 1) * f(k)
  71. })
  72. }
  73. #----------------------------------
  74. func S3(n) {
  75. (n+1) * sum(1..n, {|k|
  76. f(k)
  77. }) - sum(1..n, {|k|
  78. k * f(k)
  79. })
  80. }
  81. #----------------------------------
  82. func A1(n) {
  83. sum(1..n, {|k|
  84. f(k)
  85. })
  86. }
  87. func B1(n) {
  88. sum(1..n, {|k|
  89. f(k) * k
  90. })
  91. }
  92. func S4(n) {
  93. (n+1)*A1(n) - B1(n)
  94. }
  95. #----------------------------------
  96. func A2(n) {
  97. sum(1..floor((n+1)/2), {|k|
  98. floor(n/(2*k - 1))
  99. })
  100. }
  101. func B2(n) {
  102. sum(1..floor((n+1)/2), {|k|
  103. (2*k - 1) * faulhaber_sum(floor(n/(2*k - 1)),1)
  104. })
  105. }
  106. func S5(n) {
  107. (n+1)*A2(n) - B2(n)
  108. }
  109. #----------------------------------
  110. func G(n) {
  111. floor((n+1)/2)**2
  112. }
  113. func H(n) {
  114. var total = 0
  115. var s = n.isqrt
  116. for k in (1 .. s) {
  117. total += 2*floor(n/k)
  118. }
  119. total -= s**2
  120. return total
  121. }
  122. func A3(n) {
  123. H(n) - H(n>>1)
  124. }
  125. func B3(n) {
  126. var total = 0
  127. var s = n.isqrt
  128. for k in (1..s) {
  129. total += k*G(floor(n/k))
  130. total += k*g(k)*faulhaber(floor(n/k), 1)
  131. }
  132. total -= G(s)*faulhaber(s,1)
  133. return total
  134. }
  135. func S6(n) {
  136. (n+1)*A3(n) - B3(n)
  137. }
  138. #----------------------------------
  139. func V(n) {
  140. floor((n+1)/2)
  141. }
  142. func A4(n) {
  143. var total = 0
  144. var s = n.isqrt
  145. for k in (1..s) {
  146. total += V(floor(n/k))
  147. total += g(k)*floor(n/k)
  148. }
  149. total -= V(s)*s
  150. return total
  151. }
  152. func S7(n) {
  153. (n+1)*A4(n) - B3(n)
  154. }
  155. #----------------------------------
  156. assert_eq(F1(100), 275)
  157. assert_eq(F2(100), 275)
  158. assert_eq(S1(100), 12656)
  159. assert_eq(S2(100), 12656)
  160. assert_eq(S3(100), 12656)
  161. assert_eq(S4(100), 12656)
  162. assert_eq(S5(100), 12656)
  163. assert_eq(S6(100), 12656)
  164. assert_eq(S7(100), 12656)
  165. assert_eq(20.of(A1), 20.of(A2))
  166. assert_eq(20.of(A1), 20.of(A3))
  167. assert_eq(20.of(A1), 20.of(A4))
  168. assert_eq(20.of(B1), 20.of(B2))
  169. assert_eq(20.of(B1), 20.of(B3))
  170. for n in (1..16) {
  171. say ("S(10^#{n}) = ", S6(10**n))
  172. }
  173. __END__
  174. S(10^1) = 83
  175. S(10^2) = 12656
  176. S(10^3) = 1817711
  177. S(10^4) = 238998218
  178. S(10^5) = 29651877833
  179. S(10^6) = 3540779596783
  180. S(10^7) = 411641938861705
  181. S(10^8) = 46920649099203041
  182. S(10^9) = 5267711097612683319
  183. S(10^10) = 584335736126953554014
  184. S(10^11) = 64190036334552593839325
  185. S(10^12) = 6994649906587129113148380
  186. S(10^13) = 757029617982294029316779201
  187. S(10^14) = 81459424530700780705752580583