Open Source · 7 Languages · 900+ Problems

Project Euler Solutions

Complete solutions in C++, Python & Java — with step-by-step mathematical explanations

All Problems

Problem 498: Remainder of Polynomial Division

View on Project Euler

Project Euler Problem 498 Solution

EulerSolve provides an optimized solution for Project Euler Problem 498, Remainder of Polynomial Division, with C++, Python, Java, and a step-by-step mathematical explanation.

Problem Summary Let \(R_{n,m}(x)\) be the remainder when \(x^n\) is divided by \((x-1)^m\). For integers \(0 \le d \lt m \le n\), the quantity of interest is the absolute value of the coefficient of \(x^d\) in that remainder. The real input is enormous, so the solution cannot expand polynomials term by term; it must turn the coefficient into a direct combinatorial formula and then evaluate that formula modulo the prime \(p=999999937\). Mathematical Approach The key observation is that the remainder modulo \((x-1)^m\) is exactly the Taylor expansion of \(x^n\) around \(x=1\), truncated after degree \(m-1\). Step 1: Write the remainder as a truncated expansion around \(x=1\) Since \(x=1+(x-1)\), the binomial theorem gives $x^n=(1+(x-1))^n=\sum_{k=0}^{n}\binom{n}{k}(x-1)^k.$ When we divide by \((x-1)^m\), every term with \(k \ge m\) is a multiple of \((x-1)^m\). Therefore the unique remainder of degree less than \(m\) is $R_{n,m}(x)=\sum_{k=0}^{m-1}\binom{n}{k}(x-1)^k.$ This already explains why the code never performs polynomial long division: the remainder has a closed form immediately....

Detailed mathematical approach

Problem Summary

Let \(R_{n,m}(x)\) be the remainder when \(x^n\) is divided by \((x-1)^m\). For integers \(0 \le d \lt m \le n\), the quantity of interest is the absolute value of the coefficient of \(x^d\) in that remainder. The real input is enormous, so the solution cannot expand polynomials term by term; it must turn the coefficient into a direct combinatorial formula and then evaluate that formula modulo the prime \(p=999999937\).

Mathematical Approach

The key observation is that the remainder modulo \((x-1)^m\) is exactly the Taylor expansion of \(x^n\) around \(x=1\), truncated after degree \(m-1\).

Step 1: Write the remainder as a truncated expansion around \(x=1\)

Since \(x=1+(x-1)\), the binomial theorem gives

$x^n=(1+(x-1))^n=\sum_{k=0}^{n}\binom{n}{k}(x-1)^k.$

When we divide by \((x-1)^m\), every term with \(k \ge m\) is a multiple of \((x-1)^m\). Therefore the unique remainder of degree less than \(m\) is

$R_{n,m}(x)=\sum_{k=0}^{m-1}\binom{n}{k}(x-1)^k.$

This already explains why the code never performs polynomial long division: the remainder has a closed form immediately.

Step 2: Extract the coefficient of \(x^d\)

Inside one term \((x-1)^k\), the coefficient of \(x^d\) is

$[x^d](x-1)^k=\binom{k}{d}(-1)^{k-d},\qquad k \ge d.$

So if \(a_d\) denotes the coefficient of \(x^d\) in the remainder, then

$a_d=\sum_{k=d}^{m-1}\binom{n}{k}\binom{k}{d}(-1)^{k-d}.$

The problem asks for \(|a_d|\), not the signed coefficient itself.

Step 3: Separate the fixed part from the alternating sum

Use the standard identity

$\binom{n}{k}\binom{k}{d}=\binom{n}{d}\binom{n-d}{k-d}.$

After substituting \(t=k-d\), the coefficient becomes

$a_d=\binom{n}{d}\sum_{t=0}^{m-d-1}(-1)^t\binom{n-d}{t}.$

Now the whole problem is reduced to one alternating partial sum of binomial coefficients.

Step 4: Collapse the alternating binomial sum

For \(0 \le r \lt N\), the identity

$\sum_{t=0}^{r}(-1)^t\binom{N}{t}=(-1)^r\binom{N-1}{r}$

applies. With \(N=n-d\) and \(r=m-d-1\), we obtain

$a_d=(-1)^{m-d-1}\binom{n}{d}\binom{n-d-1}{m-d-1}.$

Hence the absolute value is

$\boxed{|a_d|=\binom{n}{d}\binom{n-d-1}{m-d-1}.}$

This closed formula is the central mathematical fact used by the implementation.

Step 5: Evaluate the formula modulo the prime \(p\)

The exact coefficient is far too large to build directly, so the computation is done in \(\mathbb{F}_p\) with

$p=999999937.$

For a prime modulus, Lucas's theorem says that if

$N=\sum_i N_i p^i,\qquad K=\sum_i K_i p^i,$

then

$\binom{N}{K}\equiv \prod_i \binom{N_i}{K_i}\pmod{p}.$

Each digit-level binomial is small enough to evaluate with the multiplicative formula

$\binom{u}{v}=\frac{u(u-1)\cdots(u-v+1)}{v!},$

and the division by \(v!\) is performed modulo \(p\) using Fermat's little theorem, namely

$q^{-1}\equiv q^{p-2}\pmod{p} \qquad (q \not\equiv 0 \pmod{p}).$

So the final answer is

$|a_d| \bmod p \equiv \binom{n}{d}\binom{n-d-1}{m-d-1}\pmod{p}.$

Worked Example: \((n,m,d)=(6,3,1)\)

The truncated expansion is

$R_{6,3}(x)=\binom{6}{0}+\binom{6}{1}(x-1)+\binom{6}{2}(x-1)^2.$

Substituting the values gives

$R_{6,3}(x)=1+6(x-1)+15(x-1)^2=15x^2-24x+10.$

The coefficient of \(x^1\) is \(-24\), so the required absolute value is \(24\).

The closed formula gives exactly the same result:

$\binom{6}{1}\binom{6-1-1}{3-1-1}=\binom{6}{1}\binom{4}{1}=6\cdot 4=24.$

How the Code Works

The implementation first handles the invalid range: if \(d \ge m\) or \(m > n\), the desired coefficient is zero. Otherwise it computes the two binomial factors from the closed formula separately modulo \(p\), and then multiplies them together modulo \(p\).

To evaluate a binomial coefficient modulo the prime, the C++, Python, and Java implementations apply Lucas's theorem digit by digit in base \(p\). For each digit pair they form the numerator and denominator multiplicatively, replace division by a modular inverse obtained from fast exponentiation, and accumulate the digit contributions into the full Lucas product.

The C++ implementation also checks the formula on small cases by comparing it with direct coefficient expansion of the truncated remainder, which confirms both the combinatorial identity and the modular computation.

Complexity Analysis

Let \(L=\lfloor \log_p n \rfloor + 1\), the number of base-\(p\) digits. Lucas's theorem reduces each large binomial to \(L\) digit-level binomials. If a digit pair is \((u,v)\), the multiplicative evaluation costs \(O(\min(v,u-v))\) modular multiplications, plus \(O(\log p)\) time for the modular inverse by fast exponentiation. Therefore the overall running time is

$O\left(\sum_{i=0}^{L-1}\min(K_i,N_i-K_i)+L\log p\right)$

for each large binomial, with only \(O(1)\) extra memory. In the actual problem, \(p\) is close to \(10^9\), so the number of base-\(p\) digits is extremely small.

Footnotes and References

  1. Problem page: https://projecteuler.net/problem=498
  2. Binomial theorem: Wikipedia — Binomial theorem
  3. Binomial coefficient: Wikipedia — Binomial coefficient
  4. Lucas's theorem: Wikipedia — Lucas's theorem
  5. Fermat's little theorem: Wikipedia — Fermat's little theorem

Mathematical approach · C++ solution · Python solution · Java solution

Previous: Problem 497 · All Project Euler solutions · Next: Problem 499

Need help with a problem? Ask me! 💡
e
✦ Euler GLM 5.2
Hi! I'm Euler. Ask me anything about Project Euler problems, math concepts, or solution approaches! 🧮