Open Source · 7 Languages · 900+ Problems

Project Euler Solutions

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

All Problems

Problem 818: SET

View on Project Euler

Project Euler Problem 818 Solution

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

Problem Summary The 81 cards of the SET deck can be modeled as the 81 points of \(D=\mathbb F_3^4\). For an \(n\)-card subset \(A\subseteq D\), let \(X(A)\) be the number of SETs contained entirely in \(A\). The problem defines $F(n)=\sum_{\substack{A\subseteq D\\|A|=n}} X(A)^4$ and asks for \(F(12)\), with the checkpoints \(F(3)=1080\) and \(F(6)=159690960\). The implemented solution does not enumerate the \(\binom{81}{12}\) subsets. Instead, it rewrites the fourth moment in terms of ordered quadruples of affine lines and counts those quadruples by the size of their union. Mathematical Approach The four attributes of a SET card each have three possible values, so \(\mathbb F_3^4\) is the natural ambient space. In that model, every valid SET is exactly a 3-point affine line. Step 1: Encode the deck as affine geometry over \(\mathbb F_3\) Encode each attribute value by \(0\), \(1\), or \(2\). Then a card becomes a vector in \(\mathbb F_3^4\). Three cards \(u,v,w\) form a SET exactly when, coordinate by coordinate, the values are either all equal or all distinct....

Detailed mathematical approach

Problem Summary

The 81 cards of the SET deck can be modeled as the 81 points of \(D=\mathbb F_3^4\). For an \(n\)-card subset \(A\subseteq D\), let \(X(A)\) be the number of SETs contained entirely in \(A\). The problem defines

$F(n)=\sum_{\substack{A\subseteq D\\|A|=n}} X(A)^4$

and asks for \(F(12)\), with the checkpoints \(F(3)=1080\) and \(F(6)=159690960\). The implemented solution does not enumerate the \(\binom{81}{12}\) subsets. Instead, it rewrites the fourth moment in terms of ordered quadruples of affine lines and counts those quadruples by the size of their union.

Mathematical Approach

The four attributes of a SET card each have three possible values, so \(\mathbb F_3^4\) is the natural ambient space. In that model, every valid SET is exactly a 3-point affine line.

Step 1: Encode the deck as affine geometry over \(\mathbb F_3\)

Encode each attribute value by \(0\), \(1\), or \(2\). Then a card becomes a vector in \(\mathbb F_3^4\). Three cards \(u,v,w\) form a SET exactly when, coordinate by coordinate, the values are either all equal or all distinct. Over \(\mathbb F_3\), both cases are equivalent to

$u+v+w=0.$

So once two cards are known, the third one is forced:

$w=-(u+v).$

Geometrically, every SET is an affine line of the form

$\{a,\ a+d,\ a+2d\},\qquad d\ne 0.$

The number of possible directions is the number of 1-dimensional subspaces of \(\mathbb F_3^4\):

$\frac{3^4-1}{3-1}=40.$

Each direction partitions the 81 points into \(81/3=27\) parallel lines, hence the total number of SETs is

$L=40\cdot 27=1080.$

Equivalently, every point lies on one line in each direction, so every card belongs to exactly \(40\) SETs.

Step 2: Rewrite the fourth moment as a sum over ordered line quadruples

For any \(n\)-card subset \(A\subseteq D\), \(X(A)\) counts how many affine lines are fully contained in \(A\). Therefore

$X(A)^4=\sum_{(\ell_1,\ell_2,\ell_3,\ell_4)} \mathbf{1}_{\ell_1\cup\ell_2\cup\ell_3\cup\ell_4\subseteq A},$

where the sum runs over ordered quadruples of SET-lines. Summing over all \(A\) with \(|A|=n\) yields

$F(n)=\sum_{(\ell_1,\ell_2,\ell_3,\ell_4)} \#\{A\subseteq D:\ |A|=n,\ \ell_1\cup\ell_2\cup\ell_3\cup\ell_4\subseteq A\}.$

This is the key transformation: instead of choosing subsets first and counting SETs afterward, we choose ordered quadruples of SETs first and then ask how many subsets contain them.

Step 3: Group everything by the union size

For one ordered quadruple \((\ell_1,\ell_2,\ell_3,\ell_4)\), define

$m=\left|\ell_1\cup\ell_2\cup\ell_3\cup\ell_4\right|.$

If that union has size \(m\), then any \(n\)-card subset containing it is formed by choosing the remaining \(n-m\) cards from the other \(81-m\) cards. Thus each such quadruple contributes

$\binom{81-m}{n-m}$

to \(F(n)\). Now define the histogram

$N_m=\#\left\{(\ell_1,\ell_2,\ell_3,\ell_4):\left|\ell_1\cup\ell_2\cup\ell_3\cup\ell_4\right|=m\right\}.$

Because each line has exactly three points, the union size can only range from \(3\) to \(12\). Therefore

$\boxed{F(n)=\sum_{m=3}^{12} N_m\binom{81-m}{n-m}.}$

The original problem has now become a finite-geometry counting problem: determine the ten integers \(N_3,N_4,\dots,N_{12}\).

Step 4: Use symmetry to count \(N_m\) in \(O(L^3)\) time

A brute-force count over all ordered quadruples would require \(L^4=1080^4\) cases. The implementations avoid that by representing each line as an 81-bit mask with exactly three set bits. Then the union size of several lines is just the popcount of the bitwise OR of those masks.

The crucial simplification is symmetry: the affine automorphism group of \(\mathbb F_3^4\) sends any line to any other line, so the union-size distribution does not depend on which first line is chosen. One may therefore fix a single line \(\ell_1\), enumerate all ordered triples \((\ell_2,\ell_3,\ell_4)\), record the resulting union sizes, and multiply the histogram by \(L=1080\) at the end.

This turns the dominant work into \(O(L^3)\) union operations instead of \(O(L^4)\), while preserving the exact values of all \(N_m\).

Worked Example: Why the checkpoint \(F(3)=1080\) is immediate

If \(n=3\), then a 3-card subset \(A\) either is a SET or it is not. In the first case \(X(A)=1\); in the second case \(X(A)=0\). Hence \(X(A)^4=X(A)\), and so

$F(3)=\sum_{\substack{A\subseteq D\\|A|=3}} X(A)=1080.$

This is exactly the first validation checkpoint used by the implementation.

The same union-size formula also explains the range of \(m\). If all four ordered lines are identical, then \(m=3\) and each quadruple contributes \(\binom{78}{n-3}\). If the four lines are pairwise disjoint, then \(m=12\) and each quadruple contributes \(\binom{69}{n-12}\). All intermediate overlap patterns fall into the bins \(m=4,5,\dots,11\).

A second checkpoint, obtained from the same histogram formula after summing all bins, is

$F(6)=159690960.$

Matching both checkpoints is strong evidence that the union-size counts are correct before evaluating the target case \(n=12\).

How the Code Works

The C++, Python, and Java implementations all follow the same mathematics. They first list the 81 points of \(\mathbb F_3^4\), then enumerate SETs by choosing pairs of points, computing the unique third point \(w=-(u+v)\), sorting each triple, and discarding duplicates. That produces exactly 1080 distinct lines.

Each line is then stored as an 81-bit mask split across machine words. The implementation fixes one reference line, scans all ordered triples of additional lines, computes the popcount of the OR-union, and increments the histogram entry for that union size. After multiplying by 1080, it has all values \(N_m\).

Finally, the implementation evaluates

$F(n)=\sum_{m=3}^{12} N_m\binom{81-m}{n-m}$

with exact integer arithmetic. The C++ and Java implementations parallelize the outer part of the triple scan across threads. The Python implementation delegates to the same compiled counting strategy. All three implementations also verify structural identities such as the total number of lines, the 40 lines through each point, and the checkpoints \(F(3)\) and \(F(6)\).

Complexity Analysis

Generating the line list is inexpensive: it comes from scanning unordered point pairs, so that stage is bounded by \(O(81^2)\) work plus deduplication. The dominant phase is the fixed-line histogram count, which performs \(O(L^3)\) iterations with \(L=1080\). Each iteration uses only a constant number of bitwise OR and popcount operations, so the method is fast enough in practice despite the large constant \(1080^3\).

Memory usage is \(O(L)\): the program stores one bit mask per line and a small histogram for the possible union sizes. No large table over subsets is needed.

Footnotes and References

  1. Problem page: https://projecteuler.net/problem=818
  2. SET (card game): Wikipedia - SET (card game)
  3. Affine space: Wikipedia - Affine space
  4. Finite field: Wikipedia - Finite field
  5. Binomial coefficient: Wikipedia - Binomial coefficient

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

Previous: Problem 817 · All Project Euler solutions · Next: Problem 819

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! 🧮