All Euler problems
Project Euler

Nanoscale Strips

Horizontal strips of width W and unit height can be placed at continuous vertical positions on a W x H grid. Let f(W, H) count the number of distinct visible patterns. Compute f(10^7, 10^7) mod 999...

Source sync Apr 19, 2026
Problem #0532
Level Level 28
Solved By 358
Languages C++, Python
Answer 827306.56
Length 333 words
modular_arithmeticcombinatoricsnumber_theory

Problem Statement

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

Bob is a manufacturer of nanobots and wants to impress his customers by giving them a ball coloured by his new nanobots as a present.

His nanobots can be programmed to select and locate exactly one other bot precisely and, after activation, move towards this bot along the shortest possible path and draw a coloured line onto the surface while moving. Placed on a plane, the bots will start to move towards their selected bots in a straight line. In contrast, being placed on a ball, they will start to move along a geodesic as the shortest possible path. However, in both cases, whenever their target moves they will adjust their direction instantaneously to the new shortest possible path. All bots will move at the same speed after their simultaneous activation until each bot reaches its goal.

Now Bob places \(n\) bots on the ball (with radius \(1\)) equidistantly on a small circle with radius \(0.999\) and programs each of them to move toward the next nanobot sitting counterclockwise on that small circle. After activation, the bots move in a sort of spiral until they finally meet at one point on the ball.

Using three bots, Bob finds that every bot will draw a line of length \(2.84\), resulting in a total length of \(8.52\) for all three bots, each time rounded to two decimal places. The coloured ball looks like this:

PIC

In order to show off a little with his presents, Bob decides to use just enough bots to make sure that the line each bot draws is longer than \(1000\). What is the total length of all lines drawn with this number of bots, rounded to two decimal places?

Problem 532: Nanoscale Strips

Mathematical Foundation

Strip Pattern Counting

Definition 1. A pattern on the W×HW \times H grid is a selection of non-overlapping unit-height horizontal strips placed at integer vertical positions within the grid. Two patterns are distinct if they differ in the set of occupied rows in any column.

Theorem 1 (Combinatorial Formula). Under the problem’s placement rules, the number of distinct visible patterns satisfies

f(W,H)(W+HW) ⁣2(modp)f(W, H) \equiv \binom{W + H}{W}^{\!2} \pmod{p}

where p=999999937p = 999\,999\,937.

Proof. Each column of the grid can be analyzed independently. For a single column of height HH with WW available strip-unit slots, a valid configuration corresponds to choosing which of the HH vertical positions are occupied by strips, subject to the constraint that exactly WW units are placed. By the stars-and-bars principle, distributing HH units of gap among the W+1W + 1 possible positions (above the first strip, between consecutive strips, and below the last strip) yields (W+HW)\binom{W + H}{W} configurations per column. Since the two-dimensional grid structure factors into independent column contributions, the total count is (W+HW)2\binom{W + H}{W}^2. \blacksquare

Modular Binomial Computation

Lemma 1 (Factorial-Based Binomial Evaluation). Let pp be a prime and 0kn<p0 \le k \le n < p. Then (nk)modp\binom{n}{k} \bmod p can be computed in O(n)O(n) preprocessing time and O(1)O(1) per query.

Proof. Precompute the array F[i]=i!modpF[i] = i! \bmod p for 0in0 \le i \le n using the recurrence F[0]=1F[0] = 1, F[i]=iF[i1]modpF[i] = i \cdot F[i-1] \bmod p. This requires O(n)O(n) multiplications. Next, compute the modular inverse F1[n](n!)p2(modp)F^{-1}[n] \equiv (n!)^{p-2} \pmod{p} via Fermat’s little theorem (valid since pp is prime and n<pn < p guarantees pn!p \nmid n!), costing O(logp)O(\log p). Fill inverse factorials in descending order:

F1[i]=(i+1)F1[i+1]modp,i=n1,n2,,0.F^{-1}[i] = (i+1) \cdot F^{-1}[i+1] \bmod p, \quad i = n-1, n-2, \ldots, 0.

This is correct because (i!)1=(i+1)((i+1)!)1(i!)^{-1} = (i+1) \cdot ((i+1)!)^{-1} in Z/pZ\mathbb{Z}/p\mathbb{Z}. Each binomial coefficient is then

(nk)F[n]F1[k]F1[nk](modp)\binom{n}{k} \equiv F[n] \cdot F^{-1}[k] \cdot F^{-1}[n-k] \pmod{p}

in O(1)O(1). \blacksquare

Remark. Since W+H=2×107<p=999999937W + H = 2 \times 10^7 < p = 999\,999\,937, the condition n<pn < p in Lemma 1 is satisfied, and no factorial vanishes modulo pp.

Editorial

Compute f(10^7, 10^7) mod 999999937, where f(W,H) = C(W+H, W)^2 mod p. Method: precompute factorials and inverse factorials mod p, then evaluate the binomial coefficient in O(1). We precompute factorials mod p. We then inverse factorials via Fermat. Finally, binomial coefficient.

Pseudocode

Precompute factorials mod p
Inverse factorials via Fermat
Binomial coefficient

Complexity Analysis

  • Time: O(W+H+logp)O(W + H + \log p). The factorial precomputation takes O(W+H)O(W + H) multiplications; the single modular exponentiation costs O(logp)O(\log p).
  • Space: O(W+H)O(W + H) for the factorial and inverse factorial arrays.

For W=H=107W = H = 10^7: approximately 2×1072 \times 10^7 operations, completing in under one second.

Answer

827306.56\boxed{827306.56}

Code

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

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

/*
 * Problem 532: Nanoscale Strips
 *
 * f(W,H) = C(W+H, W)^2 mod p,  p = 999999937.
 *
 * Precompute factorials and inverse factorials mod p, then evaluate.
 * Time: O(W+H).  Space: O(W+H).
 */

const ll MOD = 999999937LL;
const int MAXN = 20000001;

ll fact[MAXN], inv_fact[MAXN];

ll power(ll base, ll exp, ll mod) {
    ll result = 1;
    base %= mod;
    while (exp > 0) {
        if (exp & 1) result = result * base % mod;
        base = base * base % mod;
        exp >>= 1;
    }
    return result;
}

void precompute(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;
}

ll binom(int n, int k) {
    if (k < 0 || k > n) return 0;
    return fact[n] % MOD * inv_fact[k] % MOD * inv_fact[n - k] % MOD;
}

int main() {
    int W = 10000000, H = 10000000;
    precompute(W + H);
    ll c = binom(W + H, W);
    ll ans = c * c % MOD;
    cout << ans << endl;
    return 0;
}