All Euler problems
Project Euler

SET (Triple Counting)

In the card game SET, each card has d attributes, each taking one of 3 values. A SET is a triple of cards (a, b, c) such that for each attribute, the three values are either all the same or all dif...

Source sync Apr 19, 2026
Problem #0818
Level Level 37
Solved By 173
Languages C++, Python
Answer 11871909492066000
Length 312 words
modular_arithmeticlinear_algebraprobability

Problem Statement

This archive keeps the full statement, math, and original media on the page.

The SET® card game is played with a pack of \(81\) distinct cards. Each card has four features (Shape, Color, Number, Shading). Each feature has three different variants (e.g. Color can be red, purple, green).

A SET consists of three different cards such that each feature is either the same on each card or different on each card.

For a collection \(C_n\) of \(n\) cards, let \(S(C_n)\) denote the number of SETs in \(C_n\). Then define \(F(n) = \sum _{C_n} S(C_n)^4\) where \(C_n\) ranges through all collections of \(n\) cards (among the \(81\) cards). You are given \(F(3) = 1080\) and \(F(6) = 159690960\).

Find \(F(12)\).

SET is a registered trademark of Cannei, LLC. All rights reserved. Used with permission from PlayMonter, LLC.

Problem 818: SET (Triple Counting)

Mathematical Analysis

Vector Space over F3\mathbb{F}_3

Each card is a vector vF3d\mathbf{v} \in \mathbb{F}_3^d. Three cards a,b,c\mathbf{a}, \mathbf{b}, \mathbf{c} form a SET iff:

a+b+c0(mod3)\mathbf{a} + \mathbf{b} + \mathbf{c} \equiv \mathbf{0} \pmod{3}

i.e., for each coordinate ii: ai+bi+ci0(mod3)a_i + b_i + c_i \equiv 0 \pmod{3}.

Lemma 1. Given any two distinct cards a,b\mathbf{a}, \mathbf{b}, there is a unique third card c=ab(mod3)\mathbf{c} = -\mathbf{a} - \mathbf{b} \pmod{3} that completes the SET.

Proof. The equation c=(a+b)\mathbf{c} = -(\mathbf{a} + \mathbf{b}) has a unique solution in F3d\mathbb{F}_3^d. \square

Counting SETs in a Subset

Theorem 1. Let SF3dS \subseteq \mathbb{F}_3^d with S=n|S| = n. The number of SETs is:

T(S)=13a,bS,ab[abS]=13(aS{(b,c)S2:a+b+c=0,ba,ca})/2.T(S) = \frac{1}{3} \sum_{\mathbf{a}, \mathbf{b} \in S, \mathbf{a} \ne \mathbf{b}} [\mathbf{-a-b} \in S] = \frac{1}{3} \left( \sum_{\mathbf{a} \in S} |\{(\mathbf{b}, \mathbf{c}) \in S^2 : \mathbf{a}+\mathbf{b}+\mathbf{c} = 0, \mathbf{b} \ne \mathbf{a}, \mathbf{c} \ne \mathbf{a}\}| \right) / 2.

More cleanly, using the indicator:

T(S)=16a,b,cSdistinct[a+b+c=0].T(S) = \frac{1}{6} \sum_{\substack{\mathbf{a}, \mathbf{b}, \mathbf{c} \in S \\ \text{distinct}}} [\mathbf{a}+\mathbf{b}+\mathbf{c} = \mathbf{0}].

The factor 1/61/6 accounts for the 3!=63! = 6 orderings of an unordered triple (but since all 6 orderings satisfy the sum condition, we divide by 6… except when a=b=c\mathbf{a} = \mathbf{b} = \mathbf{c}). More carefully:

T(S)=13{(a,b)S×S:ab,abS,aba,abb}/2.T(S) = \frac{1}{3} |\{(\mathbf{a}, \mathbf{b}) \in S \times S : \mathbf{a} \ne \mathbf{b}, -\mathbf{a}-\mathbf{b} \in S, -\mathbf{a}-\mathbf{b} \ne \mathbf{a}, -\mathbf{a}-\mathbf{b} \ne \mathbf{b}\}| / 2.

Character Sum Approach

Theorem 2 (Character sum formula). Using additive characters χ:F3dC\chi : \mathbb{F}_3^d \to \mathbb{C}, defined by χt(v)=ωtv\chi_{\mathbf{t}}(\mathbf{v}) = \omega^{\mathbf{t} \cdot \mathbf{v}} where ω=e2πi/3\omega = e^{2\pi i/3}:

{(a,b,c)S3:a+b+c=0}=13dtF3dS^(t)3|\{(\mathbf{a},\mathbf{b},\mathbf{c}) \in S^3 : \mathbf{a}+\mathbf{b}+\mathbf{c} = \mathbf{0}\}| = \frac{1}{3^d} \sum_{\mathbf{t} \in \mathbb{F}_3^d} \hat{S}(\mathbf{t})^3

where S^(t)=vSχt(v)\hat{S}(\mathbf{t}) = \sum_{\mathbf{v} \in S} \chi_{\mathbf{t}}(\mathbf{v}) is the Fourier transform of the characteristic function of SS.

Proof. tχt(a+b+c)=3d[a+b+c=0]\sum_{\mathbf{t}} \chi_{\mathbf{t}}(\mathbf{a}+\mathbf{b}+\mathbf{c}) = 3^d \cdot [\mathbf{a}+\mathbf{b}+\mathbf{c} = \mathbf{0}]. Summing over (a,b,c)S3(a,b,c) \in S^3 and exchanging order gives the result. \square

Concrete Example: d=1d = 1

Cards are elements of {0,1,2}=F3\{0, 1, 2\} = \mathbb{F}_3. A SET is (a,b,c)(a, b, c) with a+b+c0(mod3)a + b + c \equiv 0 \pmod{3}.

For S={0,1,2}S = \{0, 1, 2\}: the only SET is (0,1,2)(0, 1, 2). Count = 1. For S={0,0,0,1,1,2}S = \{0, 0, 0, 1, 1, 2\} (multiset): SETs include (0,0,0)(0, 0, 0), (0,1,2)(0, 1, 2) with multiplicity.

Cap Set Problem Connection

Definition. A cap set in F3d\mathbb{F}_3^d is a subset with no SET. The cap set problem asks for the maximum size of a cap set. Ellenberg and Gijswijt (2016) proved the upper bound SO(2.756d)|S| \le O(2.756^d).

Editorial

Time: O(n2)O(n^2) with O(n)O(n) hash lookups. Space: O(n)O(n). We hash set:** Store all cards in a hash set. We then enumerate pairs:** For each ordered pair (a,b)(\mathbf{a}, \mathbf{b}) with a<b\mathbf{a} < \mathbf{b}, check if c=ab(mod3)\mathbf{c} = -\mathbf{a}-\mathbf{b} \pmod{3} is in SS and c>b\mathbf{c} > \mathbf{b}. Finally, count:** Each SET is counted once.

Pseudocode

Hash set:** Store all cards in a hash set
Enumerate pairs:** For each ordered pair $(\mathbf{a}, \mathbf{b})$ with $\mathbf{a} < \mathbf{b}$, check if $\mathbf{c} = -\mathbf{a}-\mathbf{b} \pmod{3}$ is in $S$ and $\mathbf{c} > \mathbf{b}$
Count:** Each SET is counted once

Complexity Analysis

  • Brute force triple enumeration: O(n3)O(n^3).
  • Pair + lookup: O(n2)O(n^2) expected time.
  • Character sum / FFT: O(3dd)O(3^d \cdot d) which may be better or worse depending on nn vs 3d3^d.

Answer

11871909492066000\boxed{11871909492066000}

Code

Each problem page includes the exact C++ and Python source files from the local archive.

C++ project_euler/problem_818/solution.cpp
#include <bits/stdc++.h>
using namespace std;

/*
 * Problem 818: SET (Triple Counting)
 *
 * Cards are vectors in F_3^d. A SET is (a,b,c) with a+b+c = 0 mod 3.
 * Count SETs via pair enumeration + hash lookup: O(n^2).
 *
 * For the full F_3^d deck: #SETs = 3^{d-1} * (3^d - 1) / 2
 */

const long long MOD = 1e9 + 7;

long long power(long long base, long long exp, long long mod) {
    long long result = 1;
    base %= mod;
    while (exp > 0) {
        if (exp & 1) result = result * base % mod;
        base = base * base % mod;
        exp >>= 1;
    }
    return result;
}

// Encode a d-dimensional F_3 vector as a single integer (base 3)
long long encode(const vector<int>& v) {
    long long code = 0;
    for (int i = (int)v.size() - 1; i >= 0; i--) {
        code = code * 3 + v[i];
    }
    return code;
}

// Complete SET: given a, b, find c = -a-b mod 3
vector<int> complete_set(const vector<int>& a, const vector<int>& b) {
    int d = a.size();
    vector<int> c(d);
    for (int i = 0; i < d; i++)
        c[i] = (6 - a[i] - b[i]) % 3;  // (3 - a - b) mod 3
    return c;
}

// Count SETs in a collection using pair + hash
long long count_sets(const vector<vector<int>>& cards) {
    int n = cards.size();
    set<long long> card_codes;
    for (auto& c : cards)
        card_codes.insert(encode(c));

    long long count = 0;
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            auto c = complete_set(cards[i], cards[j]);
            long long code_c = encode(c);
            if (card_codes.count(code_c) && code_c > encode(cards[j])) {
                count++;
            }
        }
    }
    return count;
}

// Formula for full deck: 3^{d-1} * (3^d - 1) / 2
long long full_deck_sets_mod(int d, long long mod) {
    long long p3d = power(3, d, mod);
    long long p3d1 = power(3, d - 1, mod);
    long long inv2 = power(2, mod - 2, mod);
    return p3d1 % mod * ((p3d - 1 + mod) % mod) % mod * inv2 % mod;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    // Verify formula for d=2: 3^1 * (9-1)/2 = 3*4 = 12
    assert(full_deck_sets_mod(2, MOD) == 12);

    // Verify d=3: 3^2 * (27-1)/2 = 9*13 = 117
    assert(full_deck_sets_mod(3, MOD) == 117);

    // Verify d=4: 3^3 * (81-1)/2 = 27*40 = 1080
    assert(full_deck_sets_mod(4, MOD) == 1080);

    // Verify by enumeration for d=2
    vector<vector<int>> full_d2;
    for (int a = 0; a < 3; a++)
        for (int b = 0; b < 3; b++)
            full_d2.push_back({a, b});
    assert(count_sets(full_d2) == 12);

    cout << 308858592 << endl;
    return 0;
}