Open Source · 7 Languages · 900+ Problems

Project Euler Solutions

Complete solutions in C++, Python & Java — with step-by-step mathematical explanations

All Problems

Problem 994: Counting Triangles

View on Project Euler

Project Euler Problem 994 Solution

EulerSolve provides an optimized solution for Project Euler Problem 994, Counting Triangles, with C++, Python, Java, and a step-by-step mathematical explanation.

Problem Summary For every pair \(1\le i\le m\), \(1\le j\le n\), the picture contains the segment from the lower point \((i,1)\) to the upper point \((j,2)\). A triangle is formed by three of these segments when the three pairwise intersections are real and not all the same point. Intersections at shared endpoints count, and intersections created inside other segments count as well. The target is \(T(1234\cdot 10^8,2345\cdot 10^8)\) modulo \(10^9+7\). The given checks are \(T(2,3)=8\), \(T(3,5)=146\), and \(T(12,23)=756716\). A geometric drawing is far too large, so the implementation counts triples of segments algebraically. Mathematical Approach 1. Dual view of a segment Represent the segment from \((i,1)\) to \((j,2)\) by the grid point \((i,j)\) in an \(m\times n\) rectangle. Two distinct segments \((i_1,j_1)\) and \((i_2,j_2)\) intersect exactly when $i_1=i_2,\qquad\text{or}\qquad j_1=j_2,\qquad\text{or}\qquad (i_1-i_2)(j_1-j_2)\lt 0.$ The first two cases are shared lower or upper endpoints. The third case says that the two endpoints appear in opposite order on the two horizontal lines, so the segments cross in the interior. 2. Counting triples that intersect pairwise We first count triples of segments for which every pair intersects. Some of these will later be removed because all three meet at one point....

Detailed mathematical approach

Problem Summary

For every pair \(1\le i\le m\), \(1\le j\le n\), the picture contains the segment from the lower point \((i,1)\) to the upper point \((j,2)\). A triangle is formed by three of these segments when the three pairwise intersections are real and not all the same point. Intersections at shared endpoints count, and intersections created inside other segments count as well.

The target is \(T(1234\cdot 10^8,2345\cdot 10^8)\) modulo \(10^9+7\). The given checks are \(T(2,3)=8\), \(T(3,5)=146\), and \(T(12,23)=756716\). A geometric drawing is far too large, so the implementation counts triples of segments algebraically.

Mathematical Approach

1. Dual view of a segment

Represent the segment from \((i,1)\) to \((j,2)\) by the grid point \((i,j)\) in an \(m\times n\) rectangle. Two distinct segments \((i_1,j_1)\) and \((i_2,j_2)\) intersect exactly when

$i_1=i_2,\qquad\text{or}\qquad j_1=j_2,\qquad\text{or}\qquad (i_1-i_2)(j_1-j_2)\lt 0.$

The first two cases are shared lower or upper endpoints. The third case says that the two endpoints appear in opposite order on the two horizontal lines, so the segments cross in the interior.

2. Counting triples that intersect pairwise

We first count triples of segments for which every pair intersects. Some of these will later be removed because all three meet at one point. The count splits cleanly by how many lower endpoints and upper endpoints are used.

If the triple uses three different lower endpoints and three different upper endpoints, then after the lower endpoints are ordered increasingly, the upper endpoints must be ordered decreasingly. Thus there is one valid matching for every choice of three lower and three upper endpoints:

$\binom m3\binom n3.$

If it uses three lower endpoints but only two upper endpoints, choose the three lower endpoints and an ordered pair of distinct upper endpoints; the singleton upper endpoint must be attached to the extreme lower endpoint on the side that makes it cross the other two. This gives \(\binom m3 n(n-1)\). By symmetry, the case of two lower endpoints and three upper endpoints contributes \(m(m-1)\binom n3\).

Finally, in a \(2\times 2\) rectangle of endpoints, exactly two of the four three-corner choices are pairwise intersecting. Therefore the \(2\)-by-\(2\) case contributes

$2\binom m2\binom n2={m(m-1)n(n-1)\over 2}.$

So the pairwise-intersecting candidate count is

$P(m,n)=\binom m3\binom n3+\binom m3 n(n-1)+m(m-1)\binom n3+{m(m-1)n(n-1)\over 2}.$

3. Removing triples concurrent at one point

A candidate triple fails to be a triangle precisely when the three segment-lines are concurrent. In the dual grid this is the same as the three points \((i,j)\) being collinear on a line of negative slope.

Take the two extreme dual points of such a collinear triple. Let their horizontal separation be \(A\) and their vertical separation be \(B\), with both positive. There are \((m-A)(n-B)\) ways to place those two extremes in the rectangle. The number of possible middle lattice points on the open segment between them is

$\gcd(A,B)-1.$

Hence the number of concurrent triples is

$C(m,n)=\sum_{A=1}^{m-1}\sum_{B=1}^{n-1}(\gcd(A,B)-1)(m-A)(n-B).$

4. Totient transform

The double sum above is still too large. Use the classical identity

$\gcd(A,B)=\sum_{d\mid\gcd(A,B)}\varphi(d),$

so that

$\gcd(A,B)-1=\sum_{\substack{d\mid A,\ d\mid B\\d\ge 2}}\varphi(d).$

Switching the order of summation gives

$C(m,n)=\sum_{d=2}^{\min(m,n)-1}\varphi(d) \left(\sum_{r=1}^{\lfloor(m-1)/d\rfloor}(m-dr)\right) \left(\sum_{s=1}^{\lfloor(n-1)/d\rfloor}(n-ds)\right).$

Define

$Q_m(d)=\left\lfloor {m-1\over d}\right\rfloor,\qquad A_m(d)=mQ_m(d)-d{Q_m(d)(Q_m(d)+1)\over 2}.$

Then \(C(m,n)=\sum_d \varphi(d)A_m(d)A_n(d)\).

5. Summatory totients and quotient blocks

The values \(Q_m(d)\) and \(Q_n(d)\) are constant on long intervals of \(d\). On such an interval, \(A_m(d)A_n(d)\) is a quadratic polynomial in \(d\), so only three prefix sums are required:

$\Phi_k(x)=\sum_{d\le x}d^k\varphi(d),\qquad k=0,1,2.$

The code builds these sums up to \(5\cdot 10^6\) by a linear sieve and evaluates larger arguments with the divisor-summatory recurrence

$\Phi_k(n)=\sum_{r=1}^{n}r^{k+1} -\sum_{\ell=2}^{n}\left(\sum_{d=\ell}^{h}d^k\right)\Phi_k\!\left(\left\lfloor {n\over \ell}\right\rfloor\right),$

where \(h=\left\lfloor n/\left\lfloor n/\ell\right\rfloor\right\rfloor\). Grouping equal quotients makes this recurrence fast enough for the huge target.

6. Final formula and checks

The answer is

$\boxed{T(m,n)=P(m,n)-C(m,n)\pmod {10^9+7}}.$

For \(m=2,n=3\), the concurrent sum is zero and \(P(2,3)=8\), so \(T(2,3)=8\). For \(m=3,n=5\), \(P(3,5)=150\). The only nonzero concurrent block is \(d=2\), which contributes \(4\), giving \(150-4=146\). The larger checkpoint \(T(12,23)=756716\) is also asserted in the implementation.

How the Code Works

The C++ program first initializes modular arithmetic helpers, binomial forms, and power-sum formulas up to degree three. pairwise_triangle_candidates evaluates \(P(m,n)\) directly.

TotientSummatory builds \(\varphi(d)\), \(\Phi_0\), \(\Phi_1\), and \(\Phi_2\) up to the sieve limit, then memoizes the recursive prefix calls for larger \(n\). concurrent_triples walks over quotient blocks of \(d\), expands \(A_m(d)A_n(d)\), and subtracts the required totient-weighted sum. The small brute-force checker enumerates all segment triples for \(1\le m,n\le 5\), then verifies the three official checkpoints.

Complexity Analysis

The fixed sieve costs \(O(L)\) time and memory for \(L=5\cdot 10^6\). The main summation uses quotient blocks, so the number of outer iterations is \(O(\sqrt{\min(m,n)})\), with memoized summatory-totient queries. The memory use is dominated by the three prefix arrays and the totient table.

A direct enumeration of all triples of the \(mn\) segments would be impossible. The formula replaces that \(O((mn)^3)\) geometry with arithmetic over divisors and floor-division blocks.

Footnotes and References

  1. Problem page: Project Euler 994
  2. Euler's totient function: Wikipedia - Euler's totient function
  3. Floor-sum decomposition: Wikipedia - Dirichlet hyperbola method
  4. Line arrangement: Wikipedia - Arrangement of lines

Mathematical approach · C++ solution · Python solution · Java solution

Previous: Problem 993 · All Project Euler solutions · Next: Problem 995

Need help with a problem? Ask me! 💡
e
✦ Euler GLM 5.2
Hi! I'm Euler. Ask me anything about Project Euler problems, math concepts, or solution approaches! 🧮