All Euler problems
Project Euler

Binomial Coefficients Divisible by 10

Let T(m, n) denote the number of binomial coefficients C(i, n) that are divisible by 10, for n <= i < m (where i, m, n are positive integers). Given: T(10^9, 10^7 - 10) = 989697000. Find: T(10^18,...

Source sync Apr 19, 2026
Problem #0322
Level Level 21
Solved By 558
Languages C++, Python
Answer 999998760323313995
Length 455 words
dynamic_programmingdigit_dpnumber_theory

Problem Statement

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

Let \(T(m, n)\) be the number of the binomial coefficients \(^iC_n\) that are divisible by \(10\) for \(n \le i < m\) (\(i\), \(m\) and \(n\) are positive integers).

You are given that \(T(10^9, 10^7-10) = 989697000\).

Find \(T(10^{18}, 10^{12}-10)\).

Problem 322: Binomial Coefficients Divisible by 10

Solution

Inclusion—exclusion via Lucas’ theorem

Theorem 1 (Lucas). Let pp be a prime. Write i=jijpji = \sum_j i_j p^j and n=jnjpjn = \sum_j n_j p^j in base pp. Then

(in)j(ijnj)(modp).\binom{i}{n} \equiv \prod_j \binom{i_j}{n_j} \pmod{p}.

Corollary 1. (in)≢0(modp)\binom{i}{n} \not\equiv 0 \pmod{p} if and only if ijnji_j \geq n_j for every digit position jj (digit-wise domination).

Proof. Each factor (ijnj)\binom{i_j}{n_j} is nonzero in Fp\mathbb{F}_p if and only if ijnji_j \geq n_j. The product vanishes if and only if at least one factor vanishes. \square

Definition 1. For a prime pp, let

fp(m,n)=#{i[n,m):p(in)}.f_p(m, n) = \#\bigl\{i \in [n, m) : p \nmid \binom{i}{n}\bigr\}.

For the composite modulus 10=2×510 = 2 \times 5, let

f10(m,n)=#{i[n,m):gcd ⁣((in),10)=1}.f_{10}(m, n) = \#\bigl\{i \in [n, m) : \gcd\!\bigl(\binom{i}{n}, 10\bigr) = 1\bigr\}.

Theorem 2 (Inclusion—exclusion). Since 10=2×510 = 2 \times 5 with gcd(2,5)=1\gcd(2,5)=1,

T(m,n)=(mn)f2(m,n)f5(m,n)+f10(m,n).T(m, n) = (m - n) - f_2(m, n) - f_5(m, n) + f_{10}(m, n).

Proof. For each i[n,m)i \in [n, m), define events A={2(in)}A = \{2 \mid \binom{i}{n}\} and B={5(in)}B = \{5 \mid \binom{i}{n}\}. Then 10(in)10 \mid \binom{i}{n} iff ABA \cap B holds. By inclusion—exclusion,

AB=A+BAB,|A \cup B| = |A| + |B| - |A \cap B|, AB=(mn)AB+AB|A \cap B| = (m-n) - \overline{|A|} - \overline{|B|} + \overline{|A \cup B|}

where A=f2\overline{|A|} = f_2, B=f5\overline{|B|} = f_5, and AB=f10\overline{|A \cup B|} = f_{10}. Equivalently, T=(mn)f2f5+f10T = (m-n) - f_2 - f_5 + f_{10}. \square

Single-prime digit DP

Proposition 1. For a prime pp, fp(m,n)f_p(m, n) equals the number of integers i[0,m)i \in [0, m) whose base-pp digits dominate those of nn position-by-position, minus 1 if mm itself satisfies the domination condition. This count is evaluated by a standard digit DP on the base-pp representation of mm, processing digits from the most significant to the least significant, with a single boolean state recording whether the prefix constructed so far equals that of mm (tight) or is strictly less (free).

Proof. By Corollary 1, p(in)p \nmid \binom{i}{n} iff every base-pp digit of ii is at least the corresponding digit of nn. The digit DP correctly enumerates all such ii in [0,m)[0, m) by enforcing digit-wise constraints: at each position jj, the chosen digit djd_j satisfies njdjujn_j \leq d_j \leq u_j where uj=mju_j = m_j if the prefix is tight, and uj=p1u_j = p - 1 otherwise. \square

Joint digit DP for f10f_{10}

Theorem 3. When m=10Km = 10^K, the count f10(m,n)f_{10}(m, n) is computed by a DP in base 10. At digit position kk (from the least significant), the state is a pair (c2,c5)(c_2, c_5) of carry values encoding the partially computed base-2 and base-5 representations of ii. For a base-10 digit d{0,,9}d \in \{0, \ldots, 9\} at position kk:

base-2 digitk(i)=(c2+d5k)mod2,base-5 digitk(i)=(c5+d2k)mod5,\text{base-2 digit}_k(i) = (c_2 + d \cdot 5^k) \bmod 2, \qquad \text{base-5 digit}_k(i) = (c_5 + d \cdot 2^k) \bmod 5, c2=(c2+d5k)/2,c5=(c5+d2k)/5.c_2' = \lfloor(c_2 + d \cdot 5^k)/2\rfloor, \qquad c_5' = \lfloor(c_5 + d \cdot 2^k)/5\rfloor.

The digit is accepted only if both extracted base-pp digits dominate the corresponding digits of nn. After all KK positions, the final carries must also satisfy domination for any remaining high-order digits of nn.

Proof. Since 10k=2k5k10^k = 2^k \cdot 5^k, each base-10 digit dd at position kk contributes d5kd \cdot 5^k to the base-2 representation (after factoring out powers of 2) and d2kd \cdot 2^k to the base-5 representation (after factoring out powers of 5). The carry variables c2c_2 and c5c_5 track the values (partial sum)/2k\lfloor (\text{partial sum}) / 2^{k}\rfloor and (partial sum)/5k\lfloor (\text{partial sum}) / 5^{k}\rfloor needed to reconstruct higher-order digits. Since 5k5^k is always odd, (c2+d)mod2(c_2 + d) \bmod 2 gives the correct base-2 digit at position kk. The domination constraint from Corollary 1 is enforced digit by digit. \square

Editorial

T(m, n) = #{i in [n, m) : 10 | C(i, n)}. By inclusion-exclusion on primes 2 and 5: T = (m - n) - f_2 - f_5 + f_10 where f_p counts i with p not dividing C(i,n) (digit-wise domination in base p). f_10 uses a joint base-10 digit DP tracking carry states for base-2 and base-5.

Pseudocode

    f2 = digit_dp_single_prime(m, n, 2)
    f5 = digit_dp_single_prime(m, n, 5)
    f10 = joint_digit_dp_base10(K = log10(m), n)
    Return (m - n) - f2 - f5 + f10

Complexity

  • Time: O(L2)O(L_2) for f2f_2, O(L5)O(L_5) for f5f_5 (where LpL_p is the number of base-pp digits of mm), and O(KS10)O(K \cdot |S| \cdot 10) for f10f_{10} where S|S| is the number of reachable carry states. Dominant term: O(KS)O(K \cdot |S|).
  • Space: O(S)O(|S|) per DP layer.

Answer

999998760323313995\boxed{999998760323313995}

Code

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

C++ project_euler/problem_322/solution.cpp
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pll;

vector<int> to_base(ll x, int p) {
    if (x == 0) return {0};
    vector<int> d;
    while (x > 0) { d.push_back(x % p); x /= p; }
    return d;
}

ll count_geq_digits(ll m, ll n, int p) {
    auto nd = to_base(n, p), md = to_base(m, p);
    int L = max(nd.size(), md.size());
    nd.resize(L, 0);
    md.resize(L, 0);
    reverse(nd.begin(), nd.end());
    reverse(md.begin(), md.end());

    vector<ll> dp(2, 0);
    dp[1] = 1;
    for (int pos = 0; pos < L; pos++) {
        vector<ll> ndp(2, 0);
        for (int t = 0; t < 2; t++) {
            if (!dp[t]) continue;
            int upper = t ? md[pos] : (p - 1);
            for (int d = nd[pos]; d <= upper; d++) {
                int nt = t && (d == md[pos]) ? 1 : 0;
                ndp[nt] += dp[t];
            }
        }
        dp = ndp;
    }
    ll res = dp[0] + dp[1];
    bool all_ok = true;
    for (int j = 0; j < L; j++)
        if (md[j] < nd[j]) { all_ok = false; break; }
    if (all_ok) res--;
    return res;
}

ll count_f10(ll m, ll n) {
    auto n2 = to_base(n, 2), n5 = to_base(n, 5);
    int K = (int)round(log10((double)m));

    ll n_high2 = n >> K;
    ll p5k = 1;
    for (int i = 0; i < K; i++) p5k *= 5;
    ll n_high5 = n / p5k;

    map<pll, ll> states;
    states[{0, 0}] = 1;
    ll pow5 = 1, pow2 = 1;

    for (int k = 0; k < K; k++) {
        map<pll, ll> ns;
        int n2k = (k < (int)n2.size()) ? n2[k] : 0;
        int n5k = (k < (int)n5.size()) ? n5[k] : 0;
        for (auto &[st, cnt] : states) {
            ll c2 = st.first, c5 = st.second;
            for (int d = 0; d < 10; d++) {
                if ((int)((c2 + d) % 2) < n2k) continue;
                if ((int)((c5 + d * pow2) % 5) < n5k) continue;
                ll nc2 = (c2 + d * pow5) / 2;
                ll nc5 = (c5 + d * pow2) / 5;
                ns[{nc2, nc5}] += cnt;
            }
        }
        states = ns;
        pow5 *= 5;
        pow2 *= 2;
    }

    ll total = 0;
    for (auto &[st, cnt] : states) {
        ll c2 = st.first, c5 = st.second;
        if (n_high2 > 0 && (c2 & n_high2) != n_high2) continue;
        if (n_high5 > 0) {
            auto nh = to_base(n_high5, 5), ch = to_base(c5, 5);
            bool ok = true;
            for (int j = 0; j < (int)nh.size(); j++) {
                int cj = (j < (int)ch.size()) ? ch[j] : 0;
                if (cj < nh[j]) { ok = false; break; }
            }
            if (!ok) continue;
        }
        total += cnt;
    }
    return total;
}

int main() {
    ll m = 1000000000000000000LL;
    ll n = 999999999990LL;
    ll f2 = count_geq_digits(m, n, 2);
    ll f5 = count_geq_digits(m, n, 5);
    ll f10 = count_f10(m, n);
    cout << (m - n) - f2 - f5 + f10 << endl;
    return 0;
}