Problem 929: Odd-Run Compositions

View on Project Euler

Project Euler Problem 929 Solution

EulerSolve provides an optimized solution for Project Euler Problem 929, Odd-Run Compositions, with C++, Python, Java, and a step-by-step mathematical explanation.

Problem Summary An odd-run composition of \(n\) is a composition \(n=p_1+p_2+\cdots+p_m\) in which every maximal block of equal adjacent parts has odd length. For example, \(2+1+1+1\) is valid because the run of 1's has length 3, while \(2+2+1\) is invalid because the run of 2's has length 2. The problem asks for the number \(u_{100000}\) of such compositions of \(100000\), reduced modulo \(1{,}111{,}124{,}111\). The solution does not enumerate compositions. Instead it builds a generating function for allowed runs, converts that to a divisor-sum coefficient sequence, and then extracts the required coefficient by inverting a formal power series. Mathematical Approach Let \(u_n\) be the number of odd-run compositions of \(n\), and let $$U(x)=\sum_{n\ge 0}u_nx^n,$$ with \(u_0=1\) for the empty composition. The derivation becomes clean once compositions are viewed as sequences of runs instead of sequences of individual parts. Runs of a Fixed Part Size Fix a part size \(j\ge 1\). A maximal run consisting of \(j\)'s may have length \(1,3,5,\dots\), so its contribution to the ordinary generating function is $$R_j(x)=x^j+x^{3j}+x^{5j}+\cdots=\frac{x^j}{1-x^{2j}}.$$ An odd-run composition is therefore a sequence of such runs where two consecutive runs are not allowed to have the same part size, because otherwise they would merge into a longer run....

Detailed mathematical approach

Problem Summary

An odd-run composition of \(n\) is a composition \(n=p_1+p_2+\cdots+p_m\) in which every maximal block of equal adjacent parts has odd length. For example, \(2+1+1+1\) is valid because the run of 1's has length 3, while \(2+2+1\) is invalid because the run of 2's has length 2.

The problem asks for the number \(u_{100000}\) of such compositions of \(100000\), reduced modulo \(1{,}111{,}124{,}111\). The solution does not enumerate compositions. Instead it builds a generating function for allowed runs, converts that to a divisor-sum coefficient sequence, and then extracts the required coefficient by inverting a formal power series.

Mathematical Approach

Let \(u_n\) be the number of odd-run compositions of \(n\), and let

$$U(x)=\sum_{n\ge 0}u_nx^n,$$

with \(u_0=1\) for the empty composition. The derivation becomes clean once compositions are viewed as sequences of runs instead of sequences of individual parts.

Runs of a Fixed Part Size

Fix a part size \(j\ge 1\). A maximal run consisting of \(j\)'s may have length \(1,3,5,\dots\), so its contribution to the ordinary generating function is

$$R_j(x)=x^j+x^{3j}+x^{5j}+\cdots=\frac{x^j}{1-x^{2j}}.$$

An odd-run composition is therefore a sequence of such runs where two consecutive runs are not allowed to have the same part size, because otherwise they would merge into a longer run.

Smirnov Words and the Global Generating Function

A composition can be regarded as a word over the infinite alphabet \(\{1,2,3,\dots\}\), where the letter \(j\) carries weight \(x^j\). After compressing each maximal run into one symbol, we get a word with no equal adjacent letters. For such words, the standard Smirnov-word generating function with letter weights \(y_j\) is

$$S(\{y_j\})=\frac{1}{1-\sum_{j\ge 1}\frac{y_j}{1+y_j}}.$$

One way to see this is to start from unrestricted words, whose generating function is \(1/(1-\sum z_j)\), and replace a letter \(j\) by a positive run of \(j\)'s. Then \(y_j=z_j+z_j^2+z_j^3+\cdots=z_j/(1-z_j)\), so \(z_j=y_j/(1+y_j)\).

For odd-run compositions we substitute \(y_j=R_j(x)\), which gives

$$U(x)=\frac{1}{1-\sum_{j\ge 1}\frac{R_j(x)}{1+R_j(x)}}=\frac{1}{1-\sum_{j\ge 1}\frac{x^j}{1+x^j-x^{2j}}}.$$

So the whole problem is reduced to understanding the series

$$A(x)=\sum_{j\ge 1}\frac{x^j}{1+x^j-x^{2j}}.$$

Why Fibonacci Numbers Appear

The Fibonacci generating function is

$$\sum_{m\ge 1}F_m t^m=\frac{t}{1-t-t^2},\qquad F_1=F_2=1.$$

Substituting \(t=-x^j\) yields

$$\frac{x^j}{1+x^j-x^{2j}}=\sum_{m\ge 1}(-1)^{m-1}F_m x^{jm}.$$

Now collect equal powers of \(x\). Writing

$$A(x)=\sum_{n\ge 1}a_nx^n,$$

the coefficient of \(x^n\) receives one contribution from each factorization \(n=jm\). Equivalently,

$$a_n=\sum_{d\mid n}(-1)^{d-1}F_d.$$

This divisor sum is exactly the sequence constructed by the implementations before any fast polynomial work begins.

The Coefficient Recurrence

Since \(U(x)=1/(1-A(x))\), we have

$$\bigl(1-A(x)\bigr)U(x)=1.$$

Comparing coefficients gives the fundamental recurrence

$$u_0=1,\qquad u_n=\sum_{k=1}^{n}a_k\,u_{n-k}\quad(n\ge 1).$$

This already solves the problem conceptually: once the divisor-sum coefficients \(a_k\) are known, the answer sequence is determined uniquely.

Worked Example: \(n=5\)

The first divisor-sum coefficients are

$$a_1=1,\quad a_2=0,\quad a_3=3,\quad a_4=-3,\quad a_5=6.$$

Using the recurrence,

$$u_1=1,\qquad u_2=1,\qquad u_3=4,\qquad u_4=4,$$

and then

$$u_5=a_1u_4+a_2u_3+a_3u_2+a_4u_1+a_5u_0=4+0+3-3+6=10.$$

This matches direct inspection. Valid examples include \(5\), \(1+3+1\), \(2+1+2\), \(2+1+1+1\), and \(1+1+1+1+1\). Invalid examples such as \(2+2+1\) or \(1+1+3\) fail because they contain an even-length run.

How the Code Works

Building the Coefficients of \(A(x)\)

The C++, Python, and Java implementations first generate Fibonacci numbers modulo \(1{,}111{,}124{,}111\). Then, for each \(d\), they add the signed Fibonacci value \((-1)^{d-1}F_d\) to every multiple of \(d\). After this divisor sweep, the array holds \(a_1,a_2,\dots,a_n\), the coefficients of \(A(x)\).

Recovering \(U(x)=1/(1-A(x))\)

A direct use of the coefficient recurrence is quadratic, so it is only suitable for small verification cases. For the real target \(n=100000\), the implementations form the series \(B(x)=1-A(x)\) and compute its inverse modulo \(x^{n+1}\) by Newton iteration. If \(G(x)\) is correct up to degree \(m-1\), the next approximation is

$$G_{\text{new}}(x)=G(x)\bigl(2-B(x)G(x)\bigr)\pmod{x^m}.$$

Because the constant term of \(B(x)\) is 1, this inverse exists as a formal power series. Each Newton step roughly doubles the number of correct coefficients, and the coefficient of \(x^n\) in the final inverse is exactly \(u_n\).

Fast Polynomial Multiplication

The expensive part of Newton iteration is polynomial multiplication. The C++ and Java implementations evaluate these convolutions with a number-theoretic transform under three auxiliary NTT-friendly prime moduli, then recombine the results with the Chinese remainder theorem to recover coefficients modulo \(1{,}111{,}124{,}111\). The Python implementation is a thin wrapper around the same C++ computation, so all three language entries follow the same mathematical pipeline.

Complexity Analysis

Constructing the divisor-sum coefficients costs

$$\sum_{d=1}^{n}\left\lfloor\frac{n}{d}\right\rfloor=O(n\log n).$$

The fast phase is the formal power-series inversion. With FFT-style multiplication cost \(M(n)=O(n\log n)\), Newton iteration runs in \(O(M(n)\log n)\), which here is \(O(n\log^2 n)\). Memory usage is \(O(n)\) for the coefficient arrays and transform buffers.

The slower recurrence \(u_n=\sum_{k=1}^{n}a_ku_{n-k}\) is \(O(n^2)\) and appears only as a correctness check on small inputs. The actual computation for \(n=100000\) relies on the quasi-linear series inversion.

Footnotes and References

  1. Project Euler problem page: https://projecteuler.net/problem=929
  2. Compositions of integers: Wikipedia - Composition (combinatorics)
  3. Fibonacci numbers and their generating function: Wikipedia - Fibonacci number
  4. Formal power series: Wikipedia - Formal power series
  5. Generating functions: Wikipedia - Generating function
  6. Number-theoretic transform: Wikipedia - Number-theoretic transform
  7. Chinese remainder theorem: Wikipedia - Chinese remainder theorem

Problem 929 source code

C++

#include <algorithm>
#include <array>
#include <cassert>
#include <cstdint>
#include <iostream>
#include <vector>

namespace {

using i64 = std::int64_t;
using u64 = std::uint64_t;
using u128 = unsigned __int128;

constexpr i64 kMod = 1'111'124'111LL;

struct NttMod {
    i64 mod;
    i64 primitive_root;
};

constexpr std::array<NttMod, 3> kNttMods = {
    NttMod{998'244'353LL, 3LL},
    NttMod{1'004'535'809LL, 3LL},
    NttMod{469'762'049LL, 3LL},
};

i64 mod_pow(i64 a, i64 e, i64 mod) {
    i64 r = 1 % mod;
    a %= mod;
    while (e > 0) {
        if (e & 1LL) {
            r = static_cast<i64>((static_cast<u128>(r) * a) % mod);
        }
        a = static_cast<i64>((static_cast<u128>(a) * a) % mod);
        e >>= 1LL;
    }
    return r;
}

i64 mod_inv_prime(i64 a, i64 mod) {
    return mod_pow(a, mod - 2, mod);
}

void ntt(std::vector<i64>& a, i64 mod, i64 primitive_root, bool invert) {
    const int n = static_cast<int>(a.size());

    for (int i = 1, j = 0; i < n; ++i) {
        int bit = n >> 1;
        for (; j & bit; bit >>= 1) {
            j ^= bit;
        }
        j ^= bit;
        if (i < j) {
            std::swap(a[i], a[j]);
        }
    }

    for (int len = 2; len <= n; len <<= 1) {
        const i64 wlen = mod_pow(primitive_root, (mod - 1) / len, mod);
        const i64 wlen_inv = mod_inv_prime(wlen, mod);
        const i64 step = invert ? wlen_inv : wlen;

        for (int i = 0; i < n; i += len) {
            i64 w = 1;
            for (int j = 0; j < len / 2; ++j) {
                const i64 u = a[i + j];
                const i64 v = static_cast<i64>((static_cast<u128>(a[i + j + len / 2]) * w) % mod);
                i64 x = u + v;
                if (x >= mod) {
                    x -= mod;
                }
                i64 y = u - v;
                if (y < 0) {
                    y += mod;
                }
                a[i + j] = x;
                a[i + j + len / 2] = y;
                w = static_cast<i64>((static_cast<u128>(w) * step) % mod);
            }
        }
    }

    if (invert) {
        const i64 n_inv = mod_inv_prime(n, mod);
        for (i64& x : a) {
            x = static_cast<i64>((static_cast<u128>(x) * n_inv) % mod);
        }
    }
}

std::vector<i64> convolution_single_mod(const std::vector<i64>& a,
                                        const std::vector<i64>& b,
                                        i64 mod,
                                        i64 primitive_root) {
    if (a.empty() || b.empty()) {
        return {};
    }

    if (std::min(a.size(), b.size()) <= 64) {
        std::vector<i64> out(a.size() + b.size() - 1, 0);
        for (std::size_t i = 0; i < a.size(); ++i) {
            for (std::size_t j = 0; j < b.size(); ++j) {
                out[i + j] = (out[i + j] + static_cast<i64>((static_cast<u128>(a[i]) * b[j]) % mod)) % mod;
            }
        }
        return out;
    }

    int n = 1;
    while (n < static_cast<int>(a.size() + b.size() - 1)) {
        n <<= 1;
    }

    std::vector<i64> fa(n, 0), fb(n, 0);
    for (std::size_t i = 0; i < a.size(); ++i) {
        fa[i] = a[i] % mod;
    }
    for (std::size_t i = 0; i < b.size(); ++i) {
        fb[i] = b[i] % mod;
    }

    ntt(fa, mod, primitive_root, false);
    ntt(fb, mod, primitive_root, false);

    for (int i = 0; i < n; ++i) {
        fa[i] = static_cast<i64>((static_cast<u128>(fa[i]) * fb[i]) % mod);
    }

    ntt(fa, mod, primitive_root, true);
    fa.resize(a.size() + b.size() - 1);
    return fa;
}

std::vector<i64> convolution_mod(const std::vector<i64>& a, const std::vector<i64>& b, i64 target_mod) {
    if (a.empty() || b.empty()) {
        return {};
    }

    std::array<std::vector<i64>, 3> convs;
    for (int t = 0; t < 3; ++t) {
        convs[t] = convolution_single_mod(a, b, kNttMods[t].mod, kNttMods[t].primitive_root);
    }

    const i64 p1 = kNttMods[0].mod;
    const i64 p2 = kNttMods[1].mod;
    const i64 p3 = kNttMods[2].mod;

    const i64 inv_p1_mod_p2 = mod_inv_prime(p1 % p2, p2);
    const i64 p1_mod_p3 = p1 % p3;
    const i64 p1p2_mod_p3 = static_cast<i64>((static_cast<u128>(p1_mod_p3) * (p2 % p3)) % p3);
    const i64 inv_p1p2_mod_p3 = mod_inv_prime(p1p2_mod_p3, p3);

    const i64 p1_mod_m = p1 % target_mod;
    const i64 p1p2_mod_m = static_cast<i64>((static_cast<u128>(p1_mod_m) * (p2 % target_mod)) % target_mod);

    std::vector<i64> out(convs[0].size(), 0);
    for (std::size_t i = 0; i < out.size(); ++i) {
        const i64 r1 = convs[0][i];
        const i64 r2 = convs[1][i];
        const i64 r3 = convs[2][i];

        i64 t1 = r2 - r1;
        if (t1 < 0) {
            t1 += p2;
        }
        t1 = static_cast<i64>((static_cast<u128>(t1) * inv_p1_mod_p2) % p2);

        const i64 x12_mod_p3 = (r1 + static_cast<i64>((static_cast<u128>(p1_mod_p3) * t1) % p3)) % p3;

        i64 t2 = r3 - x12_mod_p3;
        if (t2 < 0) {
            t2 += p3;
        }
        t2 = static_cast<i64>((static_cast<u128>(t2) * inv_p1p2_mod_p3) % p3);

        i64 x = r1 % target_mod;
        x += static_cast<i64>((static_cast<u128>(p1_mod_m) * (t1 % target_mod)) % target_mod);
        if (x >= target_mod) {
            x -= target_mod;
        }
        x += static_cast<i64>((static_cast<u128>(p1p2_mod_m) * (t2 % target_mod)) % target_mod);
        x %= target_mod;
        out[i] = x;
    }

    return out;
}

std::vector<i64> poly_inv_one_minus(const std::vector<i64>& b, int n) {
    std::vector<i64> inv(1, 1);

    int len = 1;
    while (len < n) {
        const int m = std::min(2 * len, n);

        std::vector<i64> b_cut(m, 0);
        for (int i = 0; i < m; ++i) {
            b_cut[i] = b[i] % kMod;
        }

        std::vector<i64> prod = convolution_mod(inv, b_cut, kMod);
        prod.resize(m, 0);

        for (int i = 0; i < m; ++i) {
            prod[i] = (kMod - prod[i]) % kMod;
        }
        prod[0] = (prod[0] + 2) % kMod;

        std::vector<i64> next = convolution_mod(inv, prod, kMod);
        next.resize(m, 0);
        inv.swap(next);

        len = m;
    }

    inv.resize(n, 0);
    return inv;
}

std::vector<i64> build_A(int n) {
    std::vector<i64> fib(n + 1, 0);
    if (n >= 1) {
        fib[1] = 1;
    }
    for (int i = 2; i <= n; ++i) {
        fib[i] = fib[i - 1] + fib[i - 2];
        if (fib[i] >= kMod) {
            fib[i] -= kMod;
        }
    }

    std::vector<i64> a(n + 1, 0);

    for (int d = 1; d <= n; ++d) {
        i64 b = fib[d];
        if ((d & 1) == 0) {
            b = (kMod - b) % kMod;
        }

        for (int m = d; m <= n; m += d) {
            a[m] += b;
            if (a[m] >= kMod) {
                a[m] -= kMod;
            }
        }
    }

    return a;
}

i64 solve_fast(int n) {
    std::vector<i64> a = build_A(n);

    std::vector<i64> one_minus_a(n + 1, 0);
    one_minus_a[0] = 1;
    for (int i = 1; i <= n; ++i) {
        one_minus_a[i] = (kMod - a[i]) % kMod;
    }

    std::vector<i64> inv = poly_inv_one_minus(one_minus_a, n + 1);
    return inv[n] % kMod;
}

i64 solve_slow(int n) {
    std::vector<i64> a = build_A(n);
    std::vector<i64> u(n + 1, 0);
    u[0] = 1;

    for (int i = 1; i <= n; ++i) {
        i64 cur = 0;
        for (int k = 1; k <= i; ++k) {
            cur += static_cast<i64>((static_cast<u128>(a[k]) * u[i - k]) % kMod);
            if (cur >= kMod) {
                cur -= kMod;
            }
        }
        u[i] = cur;
    }

    return u[n];
}

void run_validations() {
    assert(solve_slow(5) == 10);

    for (int n = 1; n <= 80; ++n) {
        assert(solve_fast(n) == solve_slow(n));
    }
}

}  // namespace

int main() {
    run_validations();
    constexpr int kN = 100'000;
    std::cout << solve_fast(kN) << '\n';
    return 0;
}

Python

from __future__ import annotations

import re
import shutil
import subprocess
from pathlib import Path

ANSWER_RE = re.compile(r"answer\s*:\s*(.+)$", re.IGNORECASE)
EQUAL_RE = re.compile(r"=\s*(.+)$")


def parse_output(stdout: str) -> str:
    lines = [line.strip() for line in stdout.splitlines() if line.strip()]
    if not lines:
        return ""
    answers = []
    equals = []
    for line in lines:
        m1 = ANSWER_RE.search(line)
        if m1:
            answers.append(m1.group(1).strip())
        m2 = EQUAL_RE.search(line)
        if m2:
            equals.append(m2.group(1).strip())
    if answers:
        return answers[-1]
    if equals:
        return equals[-1]
    return lines[-1]


def should_skip_cpp_checkpoints(src: Path) -> bool:
    try:
        text = src.read_text(encoding="utf-8", errors="ignore")
    except OSError:
        return False
    return "--skip-checkpoints" in text


def run_cpp(binary: Path, src: Path, root: Path) -> str:
    cmd = [str(binary)]
    if should_skip_cpp_checkpoints(src):
        cmd.append("--skip-checkpoints")

    try:
        return subprocess.check_output(cmd, text=True, cwd=root)
    except subprocess.CalledProcessError:
        return subprocess.check_output(cmd, text=True, cwd=src.parent)


def solve() -> str:
    problem_id = __file__.split("Euler")[-1].split(".")[0]
    root = Path(__file__).resolve().parent.parent
    src = root / "solutionsCpp" / f"Euler{problem_id}.cpp"
    binary = root / "solutionsCpp" / f".euler{problem_id}_py_bridge"

    if not binary.exists() or src.stat().st_mtime > binary.stat().st_mtime:
        compiler = shutil.which("clang++") or shutil.which("g++")
        if not compiler:
            raise RuntimeError("No C++ compiler found (clang++/g++).")
        subprocess.check_call([compiler, "-std=c++17", "-O2", str(src), "-o", str(binary)])

    output = run_cpp(binary=binary, src=src, root=root)
    parsed = parse_output(output)
    if not parsed:
        raise RuntimeError(f"Euler{problem_id} bridge produced empty output.")
    return parsed


if __name__ == "__main__":
    print(solve())

Java

import java.util.*;

public class Euler929 {

    static final long kMod = 1111124111L;

    static class NttMod {
        long mod;
        long primitiveRoot;

        NttMod(long m, long r) {
            mod = m;
            primitiveRoot = r;
        }
    }

    static final NttMod[] kNttMods = {
            new NttMod(998244353L, 3L),
            new NttMod(1004535809L, 3L),
            new NttMod(469762049L, 3L)
    };

    static long modPow(long a, long e, long mod) {
        long r = 1 % mod;
        a %= mod;
        while (e > 0) {
            if ((e & 1) != 0)
                r = (r * a) % mod;
            a = (a * a) % mod;
            e >>= 1;
        }
        return r;
    }

    static long modInvPrime(long a, long mod) {
        return modPow(a, mod - 2, mod);
    }

    static void ntt(long[] a, long mod, long primitiveRoot, boolean invert) {
        int n = a.length;
        int j = 0;
        for (int i = 1; i < n; i++) {
            int bit = n >> 1;
            for (; (j & bit) != 0; bit >>= 1)
                j ^= bit;
            j ^= bit;
            if (i < j) {
                long temp = a[i];
                a[i] = a[j];
                a[j] = temp;
            }
        }

        for (int len = 2; len <= n; len <<= 1) {
            long wlen = modPow(primitiveRoot, (mod - 1) / len, mod);
            if (invert)
                wlen = modInvPrime(wlen, mod);

            long step = wlen;
            for (int i = 0; i < n; i += len) {
                long w = 1;
                for (int k = 0; k < len / 2; k++) {
                    long u = a[i + k];
                    long v = (a[i + k + len / 2] * w) % mod;
                    long x = u + v;
                    if (x >= mod)
                        x -= mod;
                    long y = u - v;
                    if (y < 0)
                        y += mod;
                    a[i + k] = x;
                    a[i + k + len / 2] = y;
                    w = (w * step) % mod;
                }
            }
        }

        if (invert) {
            long nInv = modInvPrime(n, mod);
            for (int i = 0; i < n; i++) {
                a[i] = (a[i] * nInv) % mod;
            }
        }
    }

    static long[] convolutionSingleMod(long[] a, long[] b, long mod, long primitiveRoot) {
        if (a.length == 0 || b.length == 0)
            return new long[0];

        if (Math.min(a.length, b.length) <= 64) {
            long[] out = new long[a.length + b.length - 1];
            for (int i = 0; i < a.length; i++) {
                for (int j = 0; j < b.length; j++) {
                    out[i + j] = (out[i + j] + (a[i] * b[j]) % mod) % mod;
                }
            }
            return out;
        }

        int n = 1;
        int targetLen = a.length + b.length - 1;
        while (n < targetLen)
            n <<= 1;

        long[] fa = new long[n];
        long[] fb = new long[n];
        for (int i = 0; i < a.length; i++)
            fa[i] = a[i] % mod;
        for (int i = 0; i < b.length; i++)
            fb[i] = b[i] % mod;

        ntt(fa, mod, primitiveRoot, false);
        ntt(fb, mod, primitiveRoot, false);

        for (int i = 0; i < n; i++) {
            fa[i] = (fa[i] * fb[i]) % mod;
        }

        ntt(fa, mod, primitiveRoot, true);
        return Arrays.copyOf(fa, targetLen);
    }

    static long[] convolutionMod(long[] a, long[] b, long targetMod) {
        if (a.length == 0 || b.length == 0)
            return new long[0];

        long[][] convs = new long[3][];
        for (int t = 0; t < 3; t++) {
            convs[t] = convolutionSingleMod(a, b, kNttMods[t].mod, kNttMods[t].primitiveRoot);
        }

        long p1 = kNttMods[0].mod;
        long p2 = kNttMods[1].mod;
        long p3 = kNttMods[2].mod;

        long invP1ModP2 = modInvPrime(p1 % p2, p2);
        long p1ModP3 = p1 % p3;
        long p1P2ModP3 = (p1ModP3 * (p2 % p3)) % p3;
        long invP1P2ModP3 = modInvPrime(p1P2ModP3, p3);

        long p1ModM = p1 % targetMod;
        long p1P2ModM = (p1ModM * (p2 % targetMod)) % targetMod;

        long[] out = new long[convs[0].length];
        for (int i = 0; i < out.length; i++) {
            long r1 = convs[0][i];
            long r2 = convs[1][i];
            long r3 = convs[2][i];

            long t1 = r2 - r1;
            if (t1 < 0)
                t1 += p2;
            t1 = (t1 * invP1ModP2) % p2;

            long x12ModP3 = (r1 + p1ModP3 * t1) % p3;

            long t2 = r3 - x12ModP3;
            if (t2 < 0)
                t2 += p3;
            t2 = (t2 * invP1P2ModP3) % p3;

            long x = r1 % targetMod;
            x = (x + p1ModM * (t1 % targetMod)) % targetMod;
            x = (x + p1P2ModM * (t2 % targetMod)) % targetMod;
            out[i] = x;
        }

        return out;
    }

    static long[] polyInvOneMinus(long[] b, int n) {
        long[] inv = { 1 };
        int len = 1;
        while (len < n) {
            int m = Math.min(2 * len, n);
            long[] bCut = new long[m];
            for (int i = 0; i < m && i < b.length; i++) {
                bCut[i] = b[i] % kMod;
            }

            long[] prod = convolutionMod(inv, bCut, kMod);
            long[] nextProd = new long[m];
            for (int i = 0; i < m && i < prod.length; i++) {
                nextProd[i] = (kMod - prod[i]) % kMod;
            }
            nextProd[0] = (nextProd[0] + 2) % kMod;

            long[] nextInv = convolutionMod(inv, nextProd, kMod);
            inv = Arrays.copyOf(nextInv, m);
            len = m;
        }
        return Arrays.copyOf(inv, n);
    }

    static long[] buildA(int n) {
        long[] fib = new long[n + 1];
        if (n >= 1)
            fib[1] = 1;
        for (int i = 2; i <= n; i++) {
            fib[i] = fib[i - 1] + fib[i - 2];
            if (fib[i] >= kMod)
                fib[i] -= kMod;
        }

        long[] a = new long[n + 1];
        for (int d = 1; d <= n; d++) {
            long b = fib[d];
            if ((d % 2) == 0) {
                b = (kMod - b) % kMod;
            }
            for (int m = d; m <= n; m += d) {
                a[m] += b;
                if (a[m] >= kMod)
                    a[m] -= kMod;
            }
        }
        return a;
    }

    static long solveFast(int n) {
        long[] a = buildA(n);
        long[] oneMinusA = new long[n + 1];
        oneMinusA[0] = 1;
        for (int i = 1; i <= n; i++) {
            oneMinusA[i] = (kMod - a[i]) % kMod;
        }

        long[] inv = polyInvOneMinus(oneMinusA, n + 1);
        return inv[n] % kMod;
    }

    public static String solve() {
        return Long.toString(solveFast(100000));
    }

    public static void main(String[] args) {
        System.out.println(solve());
    }
}