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
Mathematical approach · C++ solution · Python solution · Java solution
Previous: Problem 687 · All Project Euler solutions · Next: Problem 689