Project Euler Problem 337

Let a1, a2, dots, an be an integer sequence of length n such that: - a1 = 6 - for all 1 le i lt n: phi(ai) lt phi(a{i +

Project Euler Problem 337

Solution

Answer: 85068035

Let us define a directed transition $a_i \to a_{i+1}$ whenever

$$\phi(a_i) < \phi(a_{i+1}) < a_i < a_{i+1}.$$

Then every valid sequence is simply a path in this DAG starting at $6$, and $S(N)$ counts all such paths whose final node is $\le N$.

1. Mathematical analysis

Let $dp(n)$ be the number of valid sequences ending at $n$.

Since every sequence starts at $6$,

$$dp(6)=1.$$

For $n>6$,

$$dp(n) = \sum_{\substack{x<n\ \phi(x)<\phi(n)<x}} dp(x).$$

The condition

$$\phi(x)<\phi(n)<x$$

is equivalent to:

  • $x > \phi(n)$,
  • $\phi(x) < \phi(n)$.

So if $t=\phi(n)$,

$$dp(n) = \sum_{\substack{x<n\ \phi(x)<t}} dp(x) - \sum_{\substack{x\le t\ \phi(x)<t}} dp(x).$$

Now observe a key simplification:

For every $x>1$,

$$\phi(x)<x.$$

Thus, whenever $x\le t$,

$$\phi(x)<x\le t \quad\Rightarrow\quad \phi(x)<t$$

automatically.

Hence the second sum becomes simply

$$\sum_{x\le t} dp(x).$$

Define:

$$P(k)=\sum_{x\le k}dp(x)$$

(prefix sums of $dp$).

Also maintain a Fenwick tree indexed by totient values storing

$$\sum_{\phi(x)\le v} dp(x).$$

Then:

$$dp(n) = \text{FenwickQuery}(\phi(n)-1) - P(\phi(n)).$$

Everything is modulo $10^8$.

Complexity

  • Totients via sieve: $O(N\log\log N)$
  • Each $n$ performs one Fenwick query and update: $O(\log N)$

Total:

$$O(N\log N)$$

which is feasible for $N=20{,}000{,}000$.


2. Python implementation

MOD = 100_000_000
N = 20_000_000

def solve():
    # Compute Euler totients
    phi = list(range(N + 1))

    for i in range(2, N + 1):
        if phi[i] == i:  # prime
            for j in range(i, N + 1, i):
                phi[j] -= phi[j] // i

    # Fenwick tree for sums indexed by phi value
    bit = [0] * (N + 2)

    def add(i, v):
        """Add v at index i in Fenwick tree."""
        i += 1
        while i <= N + 1:
            bit[i] += v
            bit[i] %= MOD
            i += i & -i

    def query(i):
        """Prefix sum [0..i]."""
        s = 0
        i += 1
        while i > 0:
            s += bit[i]
            i -= i & -i
        return s % MOD

    # Prefix sums of dp
    prefix = [0] * (N + 1)

    # Base case: sequence [6]
    prefix[6] = 1
    add(phi[6], 1)

    for n in range(7, N + 1):
        t = phi[n]

        # dp[n]
        val = query(t - 1) - prefix[t]
        val %= MOD

        # Add to structures
        add(t, val)
        prefix[n] = (prefix[n - 1] + val) % MOD

    return prefix[N]

print(solve())

3. Code walkthrough

Totient sieve

We initialize

phi[i] = i

and for each prime $p$,

$$\phi(k) \leftarrow \phi(k)\left(1-\frac1p\right)$$

for multiples $k$ of $p$.


Fenwick tree

We store, for each totient value $v$,

$$\sum_{\phi(x)=v} dp(x).$$

Then:

query(t - 1)

returns

$$\sum_{\phi(x)<t} dp(x).$$


Prefix correction

We must exclude all $x \le t$, because the rule requires

$$t < x.$$

Since $\phi(x)<x$, every such $x$ automatically satisfies $\phi(x)<t$, so we subtract:

prefix[t]

which equals

$$\sum_{x\le t} dp(x).$$

Thus:

val = query(t - 1) - prefix[t]

implements exactly the recurrence.


Small checks

For $N=10$, the program finds the 4 sequences:

$$(6),\ (6,8),\ (6,8,9),\ (6,10)$$

so

$$S(10)=4.$$

For $N=100$,

$$S(100)=482073668,$$

and modulo $10^8$,

$$82073668,$$

matching the statement.

For $N=10000$,

$$S(10000)\bmod 10^8 = 73808307,$$

again matching the problem.


4. Final verification

The algorithm reproduces every provided check value exactly, and the optimized computation for

$$N=20{,}000{,}000$$

gives:

Answer: 85068035