All Euler problems
Project Euler

Coloured Configurations

Consider configurations built from 25 copies of unit A and 75 copies of unit B, glued together along their vertical edges, with vertices coloured from 1984 available colours so that adjacent vertic...

Source sync May 21, 2026
Problem #0194
Level Level 12
Solved By 1,711
Languages C++, Python
Answer 61190912
Length 399 words
modular_arithmeticgraphgreedy

Problem Statement

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

Consider graphs built with the units \(A\): PIC and \(B\): PIC, where the units are glued along the vertical edges as in the graph PIC.

A configuration of type \((a, b, c)\) is a graph thus built of \(a\) units \(A\) and \(b\) units \(B\), where the graph’s vertices are coloured using up to \(c\) colours, so that no two adjacent vertices have the same colour.

The compound graph above is an example of a configuration of type \((2,2,6)\), in fact of type \((2,2,c)\) for all \(c \ge 4\).

Let \(N(a, b, c)\) be the number of configurations of type \((a, b, c)\).

For example, \(N(1,0,3) = 24\), \(N(0,2,4) = 92928\) and \(N(2,2,3) = 20736\).

Find the last \(8\) digits of \(N(25,75,1984)\).

Problem 194: Coloured Configurations

Mathematical Development

Theorem 1. (Chromatic Polynomial of KmK_m.) The number of proper nn-colourings of the complete graph KmK_m is the falling factorial

P(Km,n)=nm‾=n(n−1)(n−2)⋯(n−m+1).P(K_m, n) = n^{\underline{m}} = n(n-1)(n-2)\cdots(n-m+1).

Proof. In a proper colouring of KmK_m, every pair of vertices must receive distinct colours. Assign colours greedily: the first vertex has nn choices, the second n−1n-1, …, the mm-th vertex has n−m+1n-m+1 choices. Since KmK_m has all edges, every greedy assignment is valid and every valid colouring arises exactly once. □\square

Theorem 2. (Clique Separator Theorem.) If G=G1∪G2G = G_1 \cup G_2 where G1∩G2G_1 \cap G_2 is a clique KsK_s, then

P(G,n)=P(G1,n)⋅P(G2,n)P(Ks,n).P(G, n) = \frac{P(G_1, n) \cdot P(G_2, n)}{P(K_s, n)}.

Proof. Let S=V(G1)∩V(G2)S = V(G_1) \cap V(G_2) with ∣S∣=s|S| = s, and SS induces a clique KsK_s in both G1G_1 and G2G_2. For any proper colouring cc of GG, the restriction c∣Sc|_S is a proper colouring of KsK_s. Conversely, for a fixed proper colouring cSc_S of KsK_s:

  • The number of extensions of cSc_S to all of G1G_1 is P(G1,n)/P(Ks,n)P(G_1, n) / P(K_s, n), since every colouring of G1G_1 restricts to some colouring of SS, and by symmetry (all colourings of KsK_s are equivalent under colour permutation in terms of extension count), each colouring of SS has exactly P(G1,n)/P(Ks,n)P(G_1, n) / P(K_s, n) extensions.

  • Similarly, the number of extensions of cSc_S to G2G_2 is P(G2,n)/P(Ks,n)P(G_2, n) / P(K_s, n).

Since V(G1)∖SV(G_1) \setminus S and V(G2)∖SV(G_2) \setminus S are disjoint and share no edges, the extensions are independent. Summing over all P(Ks,n)P(K_s, n) colourings of SS:

P(G,n)=P(Ks,n)⋅P(G1,n)P(Ks,n)⋅P(G2,n)P(Ks,n)=P(G1,n)⋅P(G2,n)P(Ks,n).P(G, n) = P(K_s, n) \cdot \frac{P(G_1, n)}{P(K_s, n)} \cdot \frac{P(G_2, n)}{P(K_s, n)} = \frac{P(G_1, n) \cdot P(G_2, n)}{P(K_s, n)}.

□\square

Lemma 1. (Application.) For G=Ka∪KbG = K_a \cup K_b with Ka∩Kb=K2K_a \cap K_b = K_2 (a shared edge):

P(G,n)=na‾⋅nb‾n2‾=(n−2)a−2‾⋅nb‾.P(G, n) = \frac{n^{\underline{a}} \cdot n^{\underline{b}}}{n^{\underline{2}}} = (n-2)^{\underline{a-2}} \cdot n^{\underline{b}}.

Proof. By Theorems 1 and 2 with s=2s = 2:

P(G,n)=na‾⋅nb‾n(n−1).P(G, n) = \frac{n^{\underline{a}} \cdot n^{\underline{b}}}{n(n-1)}.

Since na‾=n(n−1)⋅(n−2)a−2‾n^{\underline{a}} = n(n-1) \cdot (n-2)^{\underline{a-2}}, the factor n(n−1)n(n-1) cancels exactly. □\square

Editorial

Fix the colours on the leftmost vertical edge first. There are c(c-1) ordered ways to do that, and once those two boundary colours are fixed, the number of valid colourings of a single unit depends only on whether the unit is of type A or type B. Enumerating the five remaining vertices of one unit gives two polynomials:

A(c)=c5−9c4+34c3−69c2+77c−38,A(c)=c^5-9c^4+34c^3-69c^2+77c-38, B(c)=c5−8c4+27c3−50c2+52c−24.B(c)=c^5-8c^4+27c^3-50c^2+52c-24.

Every time another unit is glued onto the chain, the new left boundary is again just an ordered pair of distinct colours, so the same single-unit count applies again. That means a configuration with a copies of A and b copies of B contributes

c(c−1) A(c)aB(c)bc(c-1)\,A(c)^a B(c)^b

for any fixed order of the units. The only remaining combinatorics is choosing which a of the a+b positions contain unit A, giving the binomial factor \binom{a+b}{a}. The final computation is therefore one binomial coefficient and two modular exponentiations.

Pseudocode

Set c = 1984, a = 25, b = 75, and MOD = 10^8.
Evaluate the single-unit colouring polynomials A(c) and B(c).
Compute the binomial factor C(a + b, a).

Start with the c(c-1) choices for the colours on the first vertical edge.
Multiply by A(c)^a and B(c)^b.
Multiply by C(a + b, a) to account for the placements of the A-units.
Take the result modulo MOD and return it.

Complexity Analysis

  • Time: O(a+b)O(a + b) modular multiplications. For (a,b)=(25,75)(a, b) = (25, 75), this is 98 multiplications.
  • Space: O(1)O(1).

Answer

61190912\boxed{61190912}

Code

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

C++ project_euler/problem_194/solution.cpp
#include <cassert>
#include <iostream>
#include <vector>

using namespace std;

unsigned long long unit_a_count(unsigned long long c) {
    return c * c * c * c * c - 9 * c * c * c * c + 34 * c * c * c - 69 * c * c + 77 * c - 38;
}

unsigned long long unit_b_count(unsigned long long c) {
    return c * c * c * c * c - 8 * c * c * c * c + 27 * c * c * c - 50 * c * c + 52 * c - 24;
}

unsigned long long exact_binomial_small(int n, int k) {
    if (k > n - k) {
        k = n - k;
    }
    unsigned long long result = 1;
    for (int i = 1; i <= k; ++i) {
        result = result * static_cast<unsigned long long>(n - k + i) / static_cast<unsigned long long>(i);
    }
    return result;
}

unsigned long long pow_ull(unsigned long long base, int exp) {
    unsigned long long result = 1;
    while (exp > 0) {
        if (exp & 1) {
            result *= base;
        }
        base *= base;
        exp >>= 1;
    }
    return result;
}

unsigned long long configuration_count_small(int a_units, int b_units, unsigned long long colors) {
    return colors * (colors - 1) * exact_binomial_small(a_units + b_units, a_units)
        * pow_ull(unit_a_count(colors), a_units) * pow_ull(unit_b_count(colors), b_units);
}

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

int prime_exponent_in_factorial(int n, int p) {
    int exponent = 0;
    while (n > 0) {
        n /= p;
        exponent += n;
    }
    return exponent;
}

unsigned long long binomial_mod_100_25(unsigned long long mod) {
    const int n = 100;
    const int k = 25;
    const int primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,
        53, 59, 61, 67, 71, 73, 79, 83, 89, 97};

    unsigned long long result = 1;
    for (int p : primes) {
        int exponent = prime_exponent_in_factorial(n, p)
            - prime_exponent_in_factorial(k, p)
            - prime_exponent_in_factorial(n - k, p);
        if (exponent > 0) {
            result = result * mod_pow(static_cast<unsigned long long>(p), exponent, mod) % mod;
        }
    }
    return result;
}

int main() {
    const unsigned long long mod = 100000000ULL;
    const unsigned long long colors = 1984;

    assert(configuration_count_small(1, 0, 3) == 24ULL);
    assert(configuration_count_small(0, 2, 4) == 92928ULL);
    assert(configuration_count_small(2, 2, 3) == 20736ULL);

    unsigned long long answer = colors % mod;
    answer = answer * ((colors - 1) % mod) % mod;
    answer = answer * binomial_mod_100_25(mod) % mod;
    answer = answer * mod_pow(unit_a_count(colors) % mod, 25, mod) % mod;
    answer = answer * mod_pow(unit_b_count(colors) % mod, 75, mod) % mod;

    assert(answer == 61190912ULL);
    cout << answer << '\n';
    return 0;
}