All Euler problems
Project Euler

(prime-k) factorial

For a prime p, let S(p) = sum_(k=1)^5 (p-k)! mod p. Find sum S(p) for all primes 5 <= p < 10^8.

Source sync Apr 19, 2026
Problem #0381
Level Level 07
Solved By 5,017
Languages C++, Python
Answer 139602943319822
Length 217 words
modular_arithmeticnumber_theoryalgebra

Problem Statement

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

For a prime \(p\) let \(S(p) = (\sum (p-k)!) \bmod (p)\) for \(1 \le k \le 5\).

For example, if \(p=7\),

\((7-1)! + (7-2)! + (7-3)! + (7-4)! + (7-5)! = 6! + 5! + 4! + 3! + 2! = 720+120+24+6+2 = 872\).

As \(872 \bmod (7) = 4\), \(S(7) = 4\).

It can be verified that \(\sum S(p) = 480\) for \(5 \le p < 100\).

Find \(\sum S(p)\) for \(5 \le p < 10^8\).

Problem 381: (prime-k) factorial

Mathematical Foundation

Theorem (Wilson’s Theorem). For any prime pp,

(p1)!1(modp).(p-1)! \equiv -1 \pmod{p}.

Proof. In Z/pZ\mathbb{Z}/p\mathbb{Z}, every nonzero element has a unique multiplicative inverse. The only elements equal to their own inverse are ±1\pm 1 (roots of x21x^2 \equiv 1). In the product (p1)!=12(p1)(p-1)! = 1 \cdot 2 \cdots (p-1), all other elements cancel in inverse pairs, leaving (p1)!1(1)=1(modp)(p-1)! \equiv 1 \cdot (-1) = -1 \pmod{p}. \square

Lemma (Backward Factorial Recurrence). For a prime p5p \ge 5 and 1k51 \le k \le 5:

kk(pk)!modp(p-k)! \bmod p
1p1p - 1
211
3(p1)inv(2)modp(p-1) \cdot \operatorname{inv}(2) \bmod p
4inv(6)modp\operatorname{inv}(6) \bmod p
5(p1)inv(24)modp(p-1) \cdot \operatorname{inv}(24) \bmod p

where inv(a)=ap2modp\operatorname{inv}(a) = a^{p-2} \bmod p denotes the modular inverse by Fermat’s little theorem.

Proof. We use the identity (pk)!=(p1)!/j=pk+1p1j(p-k)! = (p-1)! / \prod_{j=p-k+1}^{p-1} j modulo pp, combined with Wilson’s theorem.

  • k=1k=1: (p1)!1(modp)(p-1)! \equiv -1 \pmod{p}, so (p1)!modp=p1(p-1)! \bmod p = p - 1.

  • k=2k=2: (p2)!=(p1)!/(p1)(1)/(1)=1(modp)(p-2)! = (p-1)! / (p-1) \equiv (-1)/(-1) = 1 \pmod{p}.

  • k=3k=3: (p3)!=(p2)!/(p2)1/(2)(p+1)/2(modp)(p-3)! = (p-2)! / (p-2) \equiv 1 / (-2) \equiv -(p+1)/2 \pmod{p}.

    Since 1p1(modp)-1 \equiv p-1 \pmod{p}, this equals (p1)inv(2)modp(p-1) \cdot \operatorname{inv}(2) \bmod p.

  • k=4k=4: (p4)!=(p3)!/(p3)inv(2)3=inv(6)(modp)(p-4)! = (p-3)! / (p-3) \equiv \frac{-\operatorname{inv}(2)}{-3} = \operatorname{inv}(6) \pmod{p}.

  • k=5k=5: (p5)!=(p4)!/(p4)inv(6)4=inv(24)(p1)inv(24)(modp)(p-5)! = (p-4)! / (p-4) \equiv \frac{\operatorname{inv}(6)}{-4} = -\operatorname{inv}(24) \equiv (p-1)\cdot\operatorname{inv}(24) \pmod{p}.

\square

Theorem (Closed Form for S(p)S(p)). For any prime p5p \ge 5:

S(p)1+1inv(2)+inv(6)inv(24)(modp)S(p) \equiv -1 + 1 - \operatorname{inv}(2) + \operatorname{inv}(6) - \operatorname{inv}(24) \pmod{p}

which simplifies to

S(p)inv(24)(24+2412+41)92438(modp).S(p) \equiv \operatorname{inv}(24)\bigl(-24 + 24 - 12 + 4 - 1\bigr) \equiv -\frac{9}{24} \equiv -\frac{3}{8} \pmod{p}.

Concretely, S(p)=(p3inv(8,p))modpS(p) = \bigl(p - 3 \cdot \operatorname{inv}(8, p)\bigr) \bmod p, where inv(8,p)=8p2modp\operatorname{inv}(8, p) = 8^{p-2} \bmod p.

Proof. Multiply through by 24:

24S(p)24(1)+24(1)+24(inv(2))+24inv(6)+24(inv(24))24 \cdot S(p) \equiv 24(-1) + 24(1) + 24 \cdot (-\operatorname{inv}(2)) + 24 \cdot \operatorname{inv}(6) + 24 \cdot (-\operatorname{inv}(24)) =24+2412+41=9(modp).= -24 + 24 - 12 + 4 - 1 = -9 \pmod{p}.

Hence S(p)9inv(24)=9inv(24)3inv(8)(modp)S(p) \equiv -9 \cdot \operatorname{inv}(24) = -9 \cdot \operatorname{inv}(24) \equiv -3 \cdot \operatorname{inv}(8) \pmod{p}, since 9/24=3/89/24 = 3/8. \square

Editorial

For prime p, S(p) = sum of (p-k)! mod p for k=1..5. Using Wilson’s theorem to derive closed forms, then sieve primes.

Pseudocode

    primes = sieve_of_eratosthenes(10^8)
    total = 0
    For each p in primes where p >= 5:
        inv8 = power_mod(8, p - 2, p)
        sp = (p - 3 * inv8 % p) % p
        total += sp
    Return total

Optimization: Instead of computing 8p2modp8^{p-2} \bmod p via fast exponentiation for each prime, note that 81(p+1)/8(modp)8^{-1} \equiv (p+1)/8 \pmod{p} when 8(p+1)8 \mid (p+1), or use the extended Euclidean algorithm in O(logp)O(\log p) per prime. Alternatively, since 8=238 = 2^3, compute inv(2)=(p+1)/2\operatorname{inv}(2) = (p+1)/2 and cube it.


## Complexity Analysis

- **Time:** $O(N / \ln N \cdot \log p)$ for modular inverse per prime via fast exponentiation, or $O(N)$ with sieve. With the Sieve of Eratosthenes taking $O(N \log \log N)$ and $O(1)$ per prime using the algebraic inverse, total is $O(N \log \log N)$ where $N = 10^8$.
- **Space:** $O(N)$ for the prime sieve.

## Answer

$$
\boxed{139602943319822}
$$

Code

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

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

/*
 * Problem 381: (prime-k) factorial
 *
 * For prime p, S(p) = sum of (p-k)! mod p for k=1..5.
 * Using Wilson's theorem to derive closed forms, then sieve primes.
 *
 * Answer: 139602943319822
 */

typedef long long ll;

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

    const int N = 100000000;
    vector<bool> is_prime(N, true);
    is_prime[0] = is_prime[1] = false;

    for (int i = 2; (ll)i * i < N; i++) {
        if (is_prime[i]) {
            for (int j = i * i; j < N; j += i)
                is_prime[j] = false;
        }
    }

    // For prime p >= 5:
    // (p-1)! = p-1 mod p
    // (p-2)! = 1 mod p
    // (p-3)! = (p-1) * inv(2) mod p   [since (p-2)!/(p-2) = 1/(p-2) = -inv(2) ... let's be careful]
    // Actually:
    // (p-1)! = p-1
    // (p-2)! = (p-1)!/(p-1) = (p-1)/(p-1) = 1 ... wait, (p-1) mod p = -1
    // So (p-2)! = -1 / (p-1) = -1 * (-1) = 1 mod p. Good.
    // (p-3)! = (p-2)!/(p-2) = 1/(p-2) = inv(p-2) = -inv(2) mod p = (p - (p+1)/2) ...
    // Better: inv(p-2) = inv(-2) = -inv(2) = -(p+1)/2 mod p = (p - (p+1)/2) = (p-1)/2
    // (p-4)! = (p-3)!/(p-3) = (p-1)/2 * inv(p-3) = (p-1)/2 * (-inv(3)) = -(p-1)/(2*3) = -(p-1)*inv(6)
    // (p-5)! = (p-4)!/(p-4) = [-(p-1)*inv(6)] * inv(p-4) = [-(p-1)*inv(6)] * (-inv(4))
    //        = (p-1)*inv(24) mod p = (p-1)*inv(24)

    // S(p) = (p-1) + 1 + (p-1)/2 + (-(p-1)*inv(6)) + (p-1)*inv(24) mod p
    // S(p) = p + (p-1)*(1 + 1/2 - 1/6 + 1/24) mod p
    // Wait, let me recompute:
    // S(p) = (p-1) + 1 + (p-1)*inv(2) - (p-1)*inv(6) + (p-1)*inv(24)
    // = p + (p-1) * (inv(2) - inv(6) + inv(24))
    // = p + (p-1) * (12 - 4 + 1) * inv(24)
    // = p + (p-1) * 9 * inv(24)
    // = p + (p-1) * 3 * inv(8)
    // mod p: = 0 + (-1)*3*inv(8) = -3*inv(8) mod p = p - 3*inv(8) mod p

    // inv(8) mod p:  use Fermat's little theorem or direct
    // For p=5: inv(8) = inv(3) = 2. S = 5 - 6 = -1 = 4 mod 5.
    // Check: (4!+3!+2!+1!+0!) mod 5 = (24+6+2+1+1) mod 5 = 34 mod 5 = 4. Correct!

    ll total = 0;
    for (int p = 5; p < N; p++) {
        if (!is_prime[p]) continue;
        ll pp = p;
        // Compute inv(8) mod p
        // 8 * inv8 = 1 mod p => inv8 = (p+1)/8 if 8|(p+1), else use pow
        // Use Fermat: inv8 = pow(8, p-2, p)
        // But that's slow for every prime. Better: use the formula directly.
        // S(p) = (-3 * inv(8)) mod p
        // inv(8) = inv(2)^3. inv(2) = (p+1)/2.
        ll inv2 = (pp + 1) / 2;
        ll inv8 = inv2 % pp;
        inv8 = inv8 * inv2 % pp;
        inv8 = inv8 * inv2 % pp;
        ll s = (pp - 3 * inv8 % pp) % pp;
        total += s;
    }

    cout << total << endl;

    return 0;
}