Problem 688: Piles of Plates
View on Project EulerProject Euler Problem 688 Solution
EulerSolve provides an optimized solution for Project Euler Problem 688, Piles of Plates, with C++, Python, Java, and a step-by-step mathematical explanation.
Problem Summary Consider plate layouts whose pile heights are consecutive positive integers. If a layout uses exactly \(k\) piles and the smallest pile has height \(a \ge 1\), then the heights are $a,\ a+1,\ a+2,\ \dots,\ a+k-1.$ The total number of plates in that layout is therefore $ka+\frac{k(k-1)}{2}.$ For a limit \(n\), let \(f(n,k)\) count the valid layouts with exactly \(k\) piles and total at most \(n\). Then $f(n,k)=\max\left(0,\left\lfloor\frac{n-\frac{k(k-1)}{2}}{k}\right\rfloor\right).$ Now define $F(n)=\sum_{k\ge 1} f(n,k),\qquad S(N)=\sum_{n=1}^{N}F(n).$ The goal is to compute \(S(10^{16}) \bmod (10^9+7)\). A direct enumeration over \(n\), \(k\), and the starting height \(a\) would be far too slow, so the solution rewrites the count as a closed floor-sum over \(k\). Mathematical Approach Write $\Delta_k=\frac{k(k-1)}{2}.$ This is the extra number of plates forced by the consecutive increase \(0,1,\dots,k-1\) once the smallest pile height is fixed. Step 1: Count layouts for fixed \(n\) and fixed \(k\) If the smallest pile has height \(a\), the total is \(ka+\Delta_k\)....
Detailed mathematical approach
Problem Summary
Consider plate layouts whose pile heights are consecutive positive integers. If a layout uses exactly \(k\) piles and the smallest pile has height \(a \ge 1\), then the heights are
$a,\ a+1,\ a+2,\ \dots,\ a+k-1.$
The total number of plates in that layout is therefore
$ka+\frac{k(k-1)}{2}.$
For a limit \(n\), let \(f(n,k)\) count the valid layouts with exactly \(k\) piles and total at most \(n\). Then
$f(n,k)=\max\left(0,\left\lfloor\frac{n-\frac{k(k-1)}{2}}{k}\right\rfloor\right).$
Now define
$F(n)=\sum_{k\ge 1} f(n,k),\qquad S(N)=\sum_{n=1}^{N}F(n).$
The goal is to compute \(S(10^{16}) \bmod (10^9+7)\). A direct enumeration over \(n\), \(k\), and the starting height \(a\) would be far too slow, so the solution rewrites the count as a closed floor-sum over \(k\).
Mathematical Approach
Write
$\Delta_k=\frac{k(k-1)}{2}.$
This is the extra number of plates forced by the consecutive increase \(0,1,\dots,k-1\) once the smallest pile height is fixed.
Step 1: Count layouts for fixed \(n\) and fixed \(k\)
If the smallest pile has height \(a\), the total is \(ka+\Delta_k\). Therefore the admissible values of \(a\) satisfy
$ka+\Delta_k\le n.$
Equivalently,
$a\le \frac{n-\Delta_k}{k}.$
Since \(a\) must be a positive integer, the number of choices is exactly
$f(n,k)=\max\left(0,\left\lfloor\frac{n-\Delta_k}{k}\right\rfloor\right).$
This already explains why large \(k\) values disappear quickly: once \(\Delta_k\) is close to \(n\), there is no room left for even the smallest possible first pile.
Step 2: Swap the order of summation
Instead of computing \(F(n)\) for each \(n\) and then adding, sum over the number of piles first:
$S(N)=\sum_{n=1}^{N}\sum_{k\ge 1} f(n,k)=\sum_{k\ge 1}\sum_{n=1}^{N} f(n,k).$
For a fixed \(k\), substitute the formula from Step 1:
$\sum_{n=1}^{N} f(n,k)=\sum_{n=1}^{N}\max\left(0,\left\lfloor\frac{n-\Delta_k}{k}\right\rfloor\right).$
Now shift the index by setting \(m=n-\Delta_k\). Terms with \(m<k\) contribute \(0\), so the whole block becomes
$\sum_{m=0}^{N-\Delta_k}\left\lfloor\frac{m}{k}\right\rfloor,$
with the understanding that this contribution is zero if \(N\le \Delta_k\).
Step 3: Evaluate the floor-sum in closed form
Let
$M=N-\Delta_k.$
If \(M>0\), divide it by \(k\):
$M=uk+v,\qquad 0\le v<k.$
Then the values of \(\left\lfloor m/k\right\rfloor\) appear in blocks:
$\underbrace{0,\dots,0}_{k\text{ terms}},\ \underbrace{1,\dots,1}_{k\text{ terms}},\ \dots,\ \underbrace{u-1,\dots,u-1}_{k\text{ terms}},\ \underbrace{u,\dots,u}_{v+1\text{ terms}}.$
Therefore
$\sum_{m=0}^{M}\left\lfloor\frac{m}{k}\right\rfloor =k\sum_{j=0}^{u-1} j + u(v+1) =k\frac{u(u-1)}{2}+u(v+1).$
This removes the inner sum completely.
Step 4: Assemble the final formula
For every \(k\) with \(\Delta_k<N\), define \(u_k\) and \(v_k\) by
$N-\Delta_k=u_k k+v_k,\qquad 0\le v_k<k.$
Then
$\boxed{S(N)=\sum_{\substack{k\ge 1\\ \Delta_k<N}}\left(k\frac{u_k(u_k-1)}{2}+u_k(v_k+1)\right)\pmod{10^9+7}.}$
Once \(\Delta_k\ge N\), all later terms vanish. Since \(\Delta_k\sim k^2/2\), only \(O(\sqrt{N})\) values of \(k\) need to be examined.
Worked Example
For a local example, take \(n=14\) and \(k=3\). The possible layouts have heights
$1,2,3;\qquad 2,3,4;\qquad 3,4,5,$
with totals \(6,9,12\). The next starting height would give \(4+5+6=15>14\), so
$f(14,3)=3.$
The formula agrees:
$\Delta_3=\frac{3\cdot 2}{2}=3,\qquad \left\lfloor\frac{14-3}{3}\right\rfloor=3.$
For a cumulative example, take \(N=10\). The nonzero contributions are
$\begin{aligned} k=1&:&&\Delta_1=0,\ M=10=10\cdot 1+0,\ &&55,\\ k=2&:&&\Delta_2=1,\ M=9=4\cdot 2+1,\ &&20,\\ k=3&:&&\Delta_3=3,\ M=7=2\cdot 3+1,\ &&7,\\ k=4&:&&\Delta_4=6,\ M=4=1\cdot 4+0,\ &&1. \end{aligned}$
For \(k\ge 5\), the contribution is zero. Hence
$S(10)=55+20+7+1=83.$
How the Code Works
The C++, Python, and Java implementations all follow the same formula. They iterate over \(k=1,2,3,\dots\), compute the triangular offset \(\Delta_k=k(k-1)/2\), and stop as soon as \(\Delta_k\ge N\).
For each surviving \(k\), the implementation forms \(M=N-\Delta_k\), performs one integer division by \(k\), and obtains the quotient and remainder needed for
$k\frac{u(u-1)}{2}+u(v+1).$
Because the final answer is required modulo \(10^9+7\), the division by \(2\) is handled by multiplying with the modular inverse of \(2\). Every contribution is reduced modulo \(10^9+7\) before being added to the running total.
The C++ implementation also uses a wider integer type for intermediate products so that multiplying values near the \(10^{16}\) scale remains safe before the modular reduction. In addition, one implementation checks the closed formula against a tiny brute-force computation at \(N=100\), where both methods produce \(12656\).
Complexity Analysis
The loop stops when \(k(k-1)/2\ge N\), so the number of iterations is \(O(\sqrt{N})\). Each iteration performs only constant-time arithmetic: one triangular-number computation, one subtraction, one division with remainder, a handful of modular multiplications, and one modular addition. Therefore the total running time is \(O(\sqrt{N})\), and the extra memory usage is \(O(1)\).
Footnotes and References
- Problem page: https://projecteuler.net/problem=688
- Triangular number: Wikipedia - Triangular number
- Arithmetic progression: Wikipedia - Arithmetic progression
- Floor and ceiling functions: Wikipedia - Floor and ceiling functions
- Modular arithmetic: Wikipedia - Modular arithmetic