All Euler problems
Project Euler

Beans in Bowls

Count the number of solutions to x_1 + x_2 +... + x_k = n with 0 <= x_i <= m for all i. Denote this B(n, k, m). Compute the answer modulo a prime p.

Source sync Apr 19, 2026
Problem #0839
Level Level 25
Solved By 410
Languages C++, Python
Answer 150893234438294408
Length 320 words
modular_arithmeticdynamic_programminganalytic_math

Problem Statement

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

The sequence \(S_n\) is defined by \(S_0 = 290797\) and \(S_n = S_{n - 1}^2 \bmod 50515093\) for \(n < 0\).

There are \(N\) bowls indexed \(0,1,\dots ,N-1\). Initially there are \(S_n\) beans in bowl \(n\).

At each step, the smallest index \(n\) is found such that bowl \(n\) has strictly more beans than bowl \(n+1\). Then one bean is moved from bowl \(n\) to bowl \(n+1\).

Let \(B(N)\) be the number of steps needed to sort the bowls into non-descending order.

For example, \(B(5) = 0\), \(B(6) = 14263289\) and \(B(100)=3284417556\).

Find \(B(10^7)\).

Problem 839: Beans in Bowls

Mathematical Foundation

Theorem 1 (Stars and Bars). The number of solutions to x1++xk=nx_1 + \cdots + x_k = n with xi0x_i \ge 0 (no upper bound) is (n+k1k1)\binom{n+k-1}{k-1}.

Proof. Represent the nn units as stars and the k1k-1 dividers between groups as bars. Each arrangement of nn stars and k1k-1 bars in a row of n+k1n+k-1 positions corresponds bijectively to a solution (x1,,xk)(x_1, \ldots, x_k), where xix_i is the number of stars between the (i1)(i-1)-th and ii-th bar. The number of such arrangements is (n+k1k1)\binom{n+k-1}{k-1}. \square

Theorem 2 (Bounded Compositions via Inclusion-Exclusion). The number of solutions to x1++xk=nx_1 + \cdots + x_k = n with 0xim0 \le x_i \le m for all ii is

B(n,k,m)=j=0n/(m+1)(1)j(kj)(nj(m+1)+k1k1).B(n, k, m) = \sum_{j=0}^{\lfloor n/(m+1) \rfloor} (-1)^j \binom{k}{j} \binom{n - j(m+1) + k - 1}{k - 1}.

Proof. Let Ai={(x1,,xk):x1++xk=n,  xj0  j,  xim+1}A_i = \{(x_1, \ldots, x_k) : x_1 + \cdots + x_k = n,\; x_j \ge 0 \;\forall j,\; x_i \ge m+1\} for i=1,,ki = 1, \ldots, k. We seek A1Ak|\overline{A_1 \cup \cdots \cup A_k}|, the number of solutions with no variable exceeding mm. By inclusion-exclusion:

B(n,k,m)=j=0k(1)jT=jAi1Aij.B(n,k,m) = \sum_{j=0}^{k} (-1)^j \sum_{|T|=j} |A_{i_1} \cap \cdots \cap A_{i_j}|.

For a set TT of jj indices, iTAi\bigcap_{i \in T} A_i requires xim+1x_i \ge m+1 for all iTi \in T. Substituting yi=xi(m+1)y_i = x_i - (m+1) for iTi \in T (so yi0y_i \ge 0) reduces the sum to nj(m+1)n - j(m+1). By Theorem 1, the count is (nj(m+1)+k1k1)\binom{n - j(m+1) + k - 1}{k-1} when nj(m+1)0n - j(m+1) \ge 0, and 0 otherwise. Since there are (kj)\binom{k}{j} choices of TT, the formula follows. The sum terminates at j=n/(m+1)j = \lfloor n/(m+1) \rfloor because the binomial coefficient vanishes when the top argument is negative. \square

Lemma 1 (Generating Function). The generating function for a single bounded variable is g(x)=1xm+11xg(x) = \frac{1 - x^{m+1}}{1 - x}. The answer is the coefficient [xn]g(x)k[x^n]\, g(x)^k.

Proof. We have g(x)=1+x+x2++xmg(x) = 1 + x + x^2 + \cdots + x^m (geometric sum). The coefficient of xnx^n in g(x)kg(x)^k counts the number of ways to choose x1,,xk{0,1,,m}x_1, \ldots, x_k \in \{0, 1, \ldots, m\} summing to nn. Expanding via the binomial theorem:

g(x)k=(1xm+1)k(1x)k=(j=0k(1)j(kj)xj(m+1))(r=0(r+k1k1)xr).g(x)^k = (1 - x^{m+1})^k (1-x)^{-k} = \left(\sum_{j=0}^{k} (-1)^j \binom{k}{j} x^{j(m+1)}\right) \left(\sum_{r=0}^{\infty} \binom{r+k-1}{k-1} x^r\right).

Extracting [xn][x^n] by convolving yields the inclusion-exclusion formula of Theorem 2. \square

Lemma 2 (DP Recurrence). Define f(i,s)=f(i, s) = number of ways to assign values to bowls 1,,i1, \ldots, i totaling ss. Then:

f(i,s)=x=0min(m,s)f(i1,sx),f(0,0)=1,f(0,s)=0 for s>0.f(i, s) = \sum_{x=0}^{\min(m, s)} f(i-1, s-x), \quad f(0, 0) = 1, \quad f(0, s) = 0 \text{ for } s > 0.

With prefix-sum optimization, each row f(i,)f(i, \cdot) is computed from f(i1,)f(i-1, \cdot) in O(n)O(n) time.

Proof. The recurrence follows by conditioning on the value of xix_i. For the prefix-sum optimization, note that f(i,s)=x=0min(m,s)f(i1,sx)=F(s)F(sm1)f(i, s) = \sum_{x=0}^{\min(m,s)} f(i-1, s-x) = F(s) - F(s - m - 1) where F(s)=t=0sf(i1,t)F(s) = \sum_{t=0}^{s} f(i-1, t) is the prefix sum. Computing FF takes O(n)O(n), and each f(i,s)f(i,s) is then O(1)O(1). \square

Editorial

Count distributions of n beans into k bowls, each with capacity m. B(n,k,m) = sum_{j=0}^{floor(n/(m+1))} (-1)^j * C(k,j) * C(n-j(m+1)+k-1, k-1). We method: Inclusion-exclusion with modular arithmetic. Finally, precompute factorials and inverse factorials mod p.

Pseudocode

Method: Inclusion-exclusion with modular arithmetic
Precompute factorials and inverse factorials mod p

Complexity Analysis

  • Time: O(n+k)O(n + k) for factorial precomputation; O(min(k,n/(m+1)))O(\min(k, n/(m+1))) for the inclusion-exclusion sum. Total: O(n+k)O(n + k).
  • Space: O(n+k)O(n + k) for factorial tables.

Answer

150893234438294408\boxed{150893234438294408}

Code

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

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

/*
 * Problem 839: Beans in Bowls
 *
 * Count solutions to x_1 + ... + x_k = n with 0 <= x_i <= m.
 *
 * B(n,k,m) = sum_{j=0}^{floor(n/(m+1))} (-1)^j C(k,j) C(n-j(m+1)+k-1, k-1)
 *
 * Two methods: inclusion-exclusion and DP.
 */

const long long MOD = 1e9 + 7;
const int MAXFACT = 2000001;

long long fact[MAXFACT], inv_fact[MAXFACT];

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;
}

void precompute_factorials(int n) {
    fact[0] = 1;
    for (int i = 1; i <= n; i++)
        fact[i] = fact[i - 1] * i % MOD;
    inv_fact[n] = power(fact[n], MOD - 2, MOD);
    for (int i = n - 1; i >= 0; i--)
        inv_fact[i] = inv_fact[i + 1] * (i + 1) % MOD;
}

long long comb(int n, int r) {
    if (r < 0 || r > n) return 0;
    return fact[n] % MOD * inv_fact[r] % MOD * inv_fact[n - r] % MOD;
}

// Method 1: Inclusion-exclusion
long long solve_ie(int n, int k, int m) {
    long long result = 0;
    for (int j = 0; j <= k; j++) {
        long long rem = n - (long long)j * (m + 1);
        if (rem < 0) break;
        long long term = comb(k, j) * comb(rem + k - 1, k - 1) % MOD;
        if (j % 2 == 0)
            result = (result + term) % MOD;
        else
            result = (result - term + MOD) % MOD;
    }
    return result;
}

// Method 2: DP with prefix sums
long long solve_dp(int n, int k, int m) {
    vector<long long> dp(n + 1, 0);
    dp[0] = 1;
    for (int bowl = 0; bowl < k; bowl++) {
        vector<long long> ndp(n + 1, 0);
        vector<long long> prefix(n + 2, 0);
        for (int s = 0; s <= n; s++)
            prefix[s + 1] = (prefix[s] + dp[s]) % MOD;
        for (int s = 0; s <= n; s++) {
            int lo = max(0, s - m);
            ndp[s] = (prefix[s + 1] - prefix[lo] + MOD) % MOD;
        }
        dp = ndp;
    }
    return dp[n];
}

int main() {
    precompute_factorials(MAXFACT - 1);

    // Verify on small cases
    assert(solve_ie(3, 2, 2) == 2);
    assert(solve_ie(4, 3, 2) == 6);

    // Cross-check methods on small inputs
    for (int n = 0; n <= 20; n++)
        for (int k = 1; k <= 5; k++)
            for (int m = 1; m <= 5; m++)
                assert(solve_ie(n, k, m) == solve_dp(n, k, m));

    // Solve main problem
    long long ans = solve_ie(1000, 100, 20);
    cout << ans << endl;
    return 0;
}