Project Euler Problem 843

This problem involves an iterative procedure that begins with a circle of nge 3 integers.

Project Euler Problem 843

Solution

Answer: 2816775424692

Let the numbers on the circle be $a_0,a_1,\dots,a_{n-1}$, indexed modulo $n$.

One step of the process replaces

$$a_i \longmapsto |a_{i-1}-a_{i+1}|.$$

The key fact is that the set of possible eventual periods is completely determined modulo $2$.

Modulo $2$,

$$|x-y|\equiv x+y \pmod 2,$$

so over $\mathbb F_2$ the map becomes the linear transformation

$$T(a_i)=a_{i-1}+a_{i+1}.$$

This is the classical Rule-90 cellular automaton.


1. Algebraic formulation

Represent a state by the polynomial

$$A(x)=\sum_{i=0}^{n-1} a_i x^i$$

in the ring

$$R_n=\mathbb F_2[x]/(x^n-1).$$

Then one iteration is simply

$$A(x)\mapsto (x+x^{-1})A(x).$$

Since $x^{-1}=x^{n-1}$ in the quotient ring,

$$T(A)=(x+x^{n-1})A.$$

Thus the dynamics are multiplication by a fixed element of the finite ring $R_n$.


2. Structure of the periods

Write

$$n=2^s m,\qquad m\ \text{odd}.$$

Over $\mathbb F_2$,

$$x^n-1=(x^m-1)^{2^s}.$$

Factor $x^m-1$ into irreducibles:

$$x^m-1=\prod_i f_i(x).$$

Each factor gives an independent component of the dynamics.

For an irreducible factor $f$, let $\alpha$ be a root of $f$.

On that component, the map acts by multiplication by

$$\beta=\alpha+\alpha^{-1}.$$

The period contributed by that component is the multiplicative order of $\beta$ in the finite field generated by $\alpha$.

If $n$ has a factor $2^s$, the repeated factors introduce an extra power-of-two multiplier $2^b$ with $0\le b\le s$.

Therefore:

  • each irreducible factor contributes a basic odd period $o$,
  • possible periods are obtained by taking LCMs of the component periods,
  • and multiplying by powers of two coming from the repeated factors.

Taking the union over all $3\le n\le N$ gives the set whose sum is $S(N)$.


3. Verification on the examples

For $3\le n\le 6$:

  • $n=3$: periods ${1}$
  • $n=4$: periods ${1}$
  • $n=5$: periods ${1,3}$
  • $n=6$: periods ${1,2}$

Union:

$${1,2,3}$$

so

$$S(6)=1+2+3=6,$$

matching the statement.

For $N=30$, the computation gives exactly

$$S(30)=20381,$$

again matching the problem statement.


4. Python implementation

import math
import sympy as sp

x = sp.symbols('x')

# convert a GF(2) polynomial to bit representation
def poly_to_int(poly):
    v = 0
    for (e,), c in poly.terms():
        if int(c) & 1:
            v |= (1 << e)
    return v

# multiplication in GF(2)[x]/(modpoly)
def mul(a, b, modpoly, deg):
    r = 0
    while b:
        if b & 1:
            r ^= a
        b >>= 1
        a <<= 1
        if a >> deg:
            a ^= modpoly
    return r

def powmod(a, e, modpoly, deg):
    r = 1
    while e:
        if e & 1:
            r = mul(r, a, modpoly, deg)
        a = mul(a, a, modpoly, deg)
        e >>= 1
    return r

# multiplicative order in the finite field
def order(a, modpoly, deg):
    group_order = (1 << deg) - 1
    ans = group_order

    for p, e in sp.factorint(group_order).items():
        for _ in range(e):
            if powmod(a, ans // p, modpoly, deg) == 1:
                ans //= p
            else:
                break

    return ans

def periods_for_n(n):
    # n = 2^s * m  with m odd
    s = 0
    m = n
    while m % 2 == 0:
        s += 1
        m //= 2

    poly = sp.Poly(x**m - 1, x, modulus=2)
    factors = sp.factor_list(poly, modulus=2)[1]

    component_choices = []

    for f, _ in factors:

        # ignore x+1 (gives only the trivial fixed point)
        if f.degree() == 1:
            continue

        deg = f.degree()
        modpoly = poly_to_int(f)

        alpha = 2                      # polynomial x
        alpha_inv = powmod(alpha, m - 1, modpoly, deg)

        beta = alpha ^ alpha_inv       # alpha + alpha^{-1} over GF(2)

        odd_period = order(beta, modpoly, deg)

        choices = [1]
        for b in range(s + 1):
            choices.append(odd_period * (1 << b))

        component_choices.append(choices)

    periods = {1}

    for choices in component_choices:
        new_periods = set()
        for a in periods:
            for b in choices:
                new_periods.add(math.lcm(a, b))
        periods = new_periods

    return periods

def S(N):
    all_periods = set()

    for n in range(3, N + 1):
        all_periods |= periods_for_n(n)

    return sum(all_periods)

print(S(30))   # 20381
print(S(100))

5. Final computation

Running the program gives

$$S(100)=2816775424692.$$

The value reproduces the check $S(30)=20381$, so the computation is consistent.

Answer: 2816775424692