Problem Summary

Define

$$f(x,M)=\sum_{\substack{p\le M\\ p\mid x^{15}+1}} p,$$

and let

$$S(N,M)=\sum_{x=1}^{N} f(x,M).$$

We must evaluate this exactly for very large parameters, so checking every \(x\) separately is impossible. The key observation is that divisibility by a fixed prime depends only on residue classes modulo that prime.

Mathematical Approach

1. Reverse the order of summation

Instead of iterating over \(x\), sum prime by prime:

$$S(N,M)=\sum_{p\le M} p\,A_p(N),$$

where

$$A_p(N)=\left|\left\{1\le x\le N : x^{15}\equiv -1 \pmod p\right\}\right|.$$

So for each prime \(p\), the entire problem reduces to counting how many residue classes solve \(x^{15}\equiv -1 \pmod p\), and then counting how often those classes occur up to \(N\).

2. Count the solutions of \(x^{15}\equiv -1 \pmod p\)

For odd primes, the multiplicative group \((\mathbb{Z}/p\mathbb{Z})^\times\) is cyclic of order \(p-1\). If \(g\) is a generator and \(x=g^k\), then \(-1=g^{(p-1)/2}\), so the congruence becomes

$$15k\equiv \frac{p-1}{2}\pmod{p-1}.$$

A linear congruence \(ak\equiv b\pmod m\) has solutions exactly when \(\gcd(a,m)\mid b\), and in that case it has \(\gcd(a,m)\) distinct residue classes modulo \(m\). Therefore the number of solutions is

$$d_p=\gcd(15,p-1).$$

This always works for odd \(p\): the number \(d_p\) is an odd divisor of \(15\), hence an odd divisor of \(p-1\), and every odd divisor of \(p-1\) also divides \((p-1)/2\). The special case \(p=2\) also fits the same formula, because \(d_2=\gcd(15,1)=1\) and the unique solution is \(x\equiv 1\pmod 2\).

3. Describe all solution classes explicitly

Because \((-1)^{15}=-1\), one solution is already known: \(x\equiv -1\pmod p\). Every other solution differs from it by a 15th root of unity. The subgroup

$$U_p=\left\{u\in (\mathbb{Z}/p\mathbb{Z})^\times : u^{15}\equiv 1\pmod p\right\}$$

has exactly \(d_p\) elements. If \(r\) has exact order \(d_p\), then

$$U_p=\{r^0,r^1,\dots,r^{d_p-1}\},$$

so the full solution set is

$$h_j\equiv -r^j\pmod p,\qquad 0\le j<d_p.$$

This is exactly what the implementation uses: find one element of order \(d_p\), then walk once around the resulting geometric cycle. Since \(d_p\in\{1,3,5,15\}\), each prime produces at most 15 relevant residue classes.

4. Count integers up to \(N\) in one residue class

If \(1\le h\le p-1\), the integers \(x\le N\) with \(x\equiv h\pmod p\) are

$$h,\ h+p,\ h+2p,\ \dots,$$

so their count is

$$\left\lfloor\frac{N-h}{p}\right\rfloor+1=\left\lfloor\frac{N+p-h}{p}\right\rfloor.$$

This formula automatically becomes \(0\) when the first representative \(h\) is already larger than \(N\). Therefore the contribution of one prime is

$$C_p(N)=p\sum_{j=0}^{d_p-1}\left\lfloor\frac{N+p-h_j}{p}\right\rfloor,$$

and the final answer is

$$\boxed{S(N,M)=\sum_{p\le M} p\sum_{j=0}^{d_p-1}\left\lfloor\frac{N+p-h_j}{p}\right\rfloor.}$$

5. Worked example: \(N=10,\ M=20\)

For \(p=2\), the only class is \(h=1\), so there are \(5\) odd numbers up to \(10\), giving \(C_2=2\cdot 5=10\).

For \(p=7\), we have \(d_7=\gcd(15,6)=3\). One element of order \(3\) is \(r=4\), hence the solution classes are \(h\in\{3,5,6\}\). Up to \(10\), these occur \(2,1,1\) times respectively, so

$$C_7=7(2+1+1)=28.$$

For \(p=11\), \(d_{11}=5\), and the five classes are \(h\in\{7,6,2,8,10\}\). Each appears exactly once in \(1,\dots,10\), so

$$C_{11}=11\cdot 5=55.$$

The remaining contributing primes up to \(20\) are \(3,5,13,19\), with contributions \(9,10,26,19\). Prime \(17\) contributes \(0\), because its only solution class is \(16\pmod{17}\), which does not appear below \(10\). Thus

$$S(10,20)=10+9+10+28+55+26+19=157.$$

How the Code Works

The C++, Python, and Java implementations all follow the same number-theoretic plan. First they sieve all primes up to \(M\). For each prime, they compute \(d=\gcd(15,p-1)\), construct one element of exact order \(d\), generate the \(d\) solution classes for \(x^{15}\equiv -1\pmod p\), and add \(p\) times the number of integers up to \(N\) in each class. No search over all \(x\le N\) ever occurs.

The C++ implementation also exploits the fact that prime contributions are independent: once the prime list has been built, different ranges of primes can be processed in parallel and their partial sums added at the end.

Complexity Analysis

Generating all primes up to \(M\) with a sieve costs \(O(M\log\log M)\) time and \(O(M)\) memory in the direct form used here. After that, the work per prime is small: one gcd, a short search for an element of order \(d\), and then processing only \(d\le 15\) residue classes. So the runtime is dominated by the prime scan, not by \(N\), which is the decisive improvement over brute force.

References

  1. Problem page: https://projecteuler.net/problem=421
  2. Multiplicative groups modulo a prime: Wikipedia — Multiplicative group of integers modulo \(n\)
  3. Primitive roots: Wikipedia — Primitive root modulo \(n\)
  4. Linear congruences: Wikipedia — Linear congruence theorem
  5. Sieve of Eratosthenes: Wikipedia — Sieve of Eratosthenes

Problemzusammenfassung

Wir definieren

$$f(x,M)=\sum_{\substack{p\le M\\ p\mid x^{15}+1}} p$$

und suchen die Gesamtsumme

$$S(N,M)=\sum_{x=1}^{N} f(x,M).$$

Für die echten Parameter ist eine direkte Prüfung aller \(x\) ausgeschlossen. Der entscheidende Schritt besteht darin, nach Primzahlen zu gruppieren und nur noch Restklassen modulo \(p\) zu zählen.

Mathematischer Ansatz

1. Vertauschen der Summationsreihenfolge

Statt über \(x\) zu iterieren, schreiben wir

$$S(N,M)=\sum_{p\le M} p\,A_p(N),$$

wobei

$$A_p(N)=\left|\left\{1\le x\le N : x^{15}\equiv -1 \pmod p\right\}\right|$$

die Anzahl der passenden Zahlen für ein festes \(p\) bezeichnet. Damit zerfällt das Problem in voneinander unabhängige Primzahlbeiträge.

2. Anzahl der Lösungen von \(x^{15}\equiv -1 \pmod p\)

Für ungerade Primzahlen ist \((\mathbb{Z}/p\mathbb{Z})^\times\) zyklisch der Ordnung \(p-1\). Mit einem Erzeuger \(g\) und \(x=g^k\) wird die Kongruenz zu

$$15k\equiv \frac{p-1}{2}\pmod{p-1},$$

denn \(-1=g^{(p-1)/2}\). Eine lineare Kongruenz \(ak\equiv b\pmod m\) ist genau dann lösbar, wenn \(\gcd(a,m)\mid b\), und besitzt dann \(\gcd(a,m)\) verschiedene Klassen. Also ist die Lösungsanzahl

$$d_p=\gcd(15,p-1).$$

Da \(d_p\) ein ungerader Teiler von \(15\) ist, teilt \(d_p\) bei ungeradem \(p\) automatisch auch \((p-1)/2\). Deshalb existieren stets genau \(d_p\) Lösungen. Auch \(p=2\) passt in dieselbe Formel: \(d_2=\gcd(15,1)=1\), und die einzige Lösung ist \(x\equiv 1\pmod 2\).

3. Explizite Beschreibung aller Restklassen

Weil \((-1)^{15}=-1\) gilt, ist \(-1\) selbst eine Lösung. Alle weiteren Lösungen erhält man durch Multiplikation mit 15-ten Einheitswurzeln. Die Untergruppe

$$U_p=\left\{u\in (\mathbb{Z}/p\mathbb{Z})^\times : u^{15}\equiv 1\pmod p\right\}$$

hat genau \(d_p\) Elemente. Wählt man ein Element \(r\) von exakter Ordnung \(d_p\), dann ist

$$U_p=\{r^0,r^1,\dots,r^{d_p-1}\},$$

und damit lauten die Lösungen

$$h_j\equiv -r^j\pmod p,\qquad 0\le j<d_p.$$

Genau diese Struktur nutzt die Implementierung: Es wird ein Element der Ordnung \(d_p\) gefunden, danach wird der Zyklus einmal vollständig durchlaufen. Weil \(d_p\in\{1,3,5,15\}\) gilt, müssen pro Primzahl höchstens 15 Klassen betrachtet werden.

4. Wie viele Zahlen bis \(N\) liegen in einer Klasse?

Für \(1\le h\le p-1\) sind die Zahlen mit \(x\equiv h\pmod p\) gleich

$$h,\ h+p,\ h+2p,\ \dots,$$

also ist ihre Anzahl

$$\left\lfloor\frac{N-h}{p}\right\rfloor+1=\left\lfloor\frac{N+p-h}{p}\right\rfloor.$$

Falls \(h>N\), liefert dieselbe Formel automatisch \(0\). Der Beitrag einer Primzahl ist daher

$$C_p(N)=p\sum_{j=0}^{d_p-1}\left\lfloor\frac{N+p-h_j}{p}\right\rfloor,$$

und insgesamt folgt

$$\boxed{S(N,M)=\sum_{p\le M} p\sum_{j=0}^{d_p-1}\left\lfloor\frac{N+p-h_j}{p}\right\rfloor.}$$

5. Beispiel: \(N=10,\ M=20\)

Für \(p=2\) gibt es nur die Klasse \(h=1\). Unter \(1,\dots,10\) liegen genau \(5\) ungerade Zahlen, also \(C_2=10\).

Für \(p=7\) ist \(d_7=\gcd(15,6)=3\). Mit einem Element \(r=4\) der Ordnung \(3\) entstehen die Klassen \(h\in\{3,5,6\}\). Diese treten bis \(10\) mit Häufigkeiten \(2,1,1\) auf, somit

$$C_7=7(2+1+1)=28.$$

Für \(p=11\) ist \(d_{11}=5\), und die fünf Klassen sind \(h\in\{7,6,2,8,10\}\). Jede kommt in \(1,\dots,10\) genau einmal vor, daher

$$C_{11}=11\cdot 5=55.$$

Die übrigen beitragenden Primzahlen bis \(20\) sind \(3,5,13,19\) mit Beiträgen \(9,10,26,19\). Dagegen liefert \(17\) keinen Beitrag, weil seine einzige Lösungsklasse \(16\pmod{17}\) unterhalb von \(10\) nicht vorkommt. Also

$$S(10,20)=10+9+10+28+55+26+19=157.$$

Wie der Code arbeitet

Die C++-, Python- und Java-Implementierungen setzen exakt diese Herleitung um. Zuerst werden alle Primzahlen bis \(M\) gesiebt. Für jede Primzahl wird \(d=\gcd(15,p-1)\) berechnet, dann ein Element exakter Ordnung \(d\) bestimmt, daraus die \(d\) Lösungsklassen von \(x^{15}\equiv -1\pmod p\) erzeugt und schließlich \(p\) mal die Anzahl der Vorkommen jeder Klasse bis \(N\) addiert.

Die C++-Version nutzt zusätzlich aus, dass die Primzahlbeiträge unabhängig sind: Nach dem Sieben kann man verschiedene Primzahlbereiche parallel auswerten und die Teilsummen am Ende addieren.

Komplexitätsanalyse

Das Primzahlsieb bis \(M\) kostet in der hier verwendeten direkten Form \(O(M\log\log M)\) Zeit und \(O(M)\) Speicher. Danach ist der Aufwand pro Primzahl klein: ein ggT, eine kurze Suche nach einem Element der Ordnung \(d\) und anschließend nur \(d\le 15\) Restklassen. Die Laufzeit hängt damit im Wesentlichen von der Primzahlerzeugung ab und nicht von der Größe von \(N\).

Quellen

  1. Problemseite: https://projecteuler.net/problem=421
  2. Multiplikative Gruppe modulo \(n\): Wikipedia — Multiplikative Gruppe
  3. Primitivwurzel: Wikipedia — Primitivwurzel modulo \(n\)
  4. Lineare Kongruenzen: Wikipedia — Kongruenz in der Zahlentheorie
  5. Sieb des Eratosthenes: Wikipedia — Sieb des Eratosthenes

Problem Özeti

Önce

$$f(x,M)=\sum_{\substack{p\le M\\ p\mid x^{15}+1}} p$$

tanımını yapalım. Aradığımız toplam ise

$$S(N,M)=\sum_{x=1}^{N} f(x,M).$$

Gerçek parametrelerde her \(x\) için tüm asalları tek tek sınamak mümkün değildir. Bu yüzden çözüm, toplamı asal bazında yeniden düzenleyip her asal için yalnızca uygun kalan sınıflarını sayar.

Matematiksel Yaklaşım

1. Toplam sırasını ters çevirme

\(x\) üzerinden gitmek yerine

$$S(N,M)=\sum_{p\le M} p\,A_p(N)$$

yazarız; burada

$$A_p(N)=\left|\left\{1\le x\le N : x^{15}\equiv -1 \pmod p\right\}\right|$$

sabit bir asal için uygun \(x\) sayısını gösterir. Böylece problem, her asalın katkısını bağımsız hesaplama işine dönüşür.

2. \(x^{15}\equiv -1 \pmod p\) denkleminin çözüm sayısı

Tek asal \(p\) için \((\mathbb{Z}/p\mathbb{Z})^\times\) grubu \(p-1\) mertebeli çevrimsel bir gruptur. Bir üreteç \(g\) seçip \(x=g^k\) yazarsak, \(-1=g^{(p-1)/2}\) olduğundan denklem

$$15k\equiv \frac{p-1}{2}\pmod{p-1}$$

haline gelir. Genel olarak \(ak\equiv b\pmod m\) doğrusal kongruensi ancak \(\gcd(a,m)\mid b\) ise çözülür ve bu durumda \(\gcd(a,m)\) adet çözüm sınıfı vardır. O halde çözüm sayısı

$$d_p=\gcd(15,p-1)$$

olur. Bu sayı her zaman işe yarar: \(d_p\), 15'in tek bölenlerinden biridir; dolayısıyla \(p-1\)'in tek bir böleni olarak \((p-1)/2\)'yi de böler. \(p=2\) durumu da uyumludur; \(d_2=\gcd(15,1)=1\) ve tek çözüm \(x\equiv 1\pmod 2\)'dir.

3. Tüm çözüm sınıflarını üretme

\((-1)^{15}=-1\) olduğu için \(-1\) zaten bir çözümdür. Diğer çözümler, bunun 15'inci birim kökleriyle çarpılmasıyla elde edilir. Şu altgrup

$$U_p=\left\{u\in (\mathbb{Z}/p\mathbb{Z})^\times : u^{15}\equiv 1\pmod p\right\}$$

tam olarak \(d_p\) eleman içerir. Eğer \(r\) elemanının mertebesi tam olarak \(d_p\) ise

$$U_p=\{r^0,r^1,\dots,r^{d_p-1}\}$$

ve çözüm sınıfları

$$h_j\equiv -r^j\pmod p,\qquad 0\le j<d_p$$

biçimindedir. Uygulama tam olarak bunu yapar: önce mertebesi \(d_p\) olan bir eleman bulur, sonra bu geometrik döngü üzerinde bir tur atar. Çünkü \(d_p\in\{1,3,5,15\}\), her asal için en fazla 15 kalan sınıfı incelenir.

4. Tek bir kalan sınıfındaki sayıların sayılması

\(1\le h\le p-1\) için \(x\equiv h\pmod p\) koşulunu sağlayan sayılar

$$h,\ h+p,\ h+2p,\ \dots$$

şeklindedir. Bunların \(N\)'e kadar sayısı

$$\left\lfloor\frac{N-h}{p}\right\rfloor+1=\left\lfloor\frac{N+p-h}{p}\right\rfloor$$

olur. Eğer \(h>N\) ise aynı formül otomatik olarak \(0\) verir. Bu nedenle bir asalın katkısı

$$C_p(N)=p\sum_{j=0}^{d_p-1}\left\lfloor\frac{N+p-h_j}{p}\right\rfloor$$

ve toplam sonuç

$$\boxed{S(N,M)=\sum_{p\le M} p\sum_{j=0}^{d_p-1}\left\lfloor\frac{N+p-h_j}{p}\right\rfloor}$$

şeklindedir.

5. Örnek: \(N=10,\ M=20\)

\(p=2\) için tek sınıf \(h=1\)'dir. \(10\)'a kadar \(5\) tek sayı bulunduğundan \(C_2=10\).

\(p=7\) için \(d_7=\gcd(15,6)=3\) olur. Mertebesi \(3\) olan bir eleman \(r=4\) seçilirse çözüm sınıfları \(h\in\{3,5,6\}\) elde edilir. Bunlar \(1,\dots,10\) aralığında sırasıyla \(2,1,1\) kez görülür; dolayısıyla

$$C_7=7(2+1+1)=28.$$

\(p=11\) için \(d_{11}=5\) ve çözüm sınıfları \(h\in\{7,6,2,8,10\}\) olur. Her biri \(1\) kez geldiği için

$$C_{11}=11\cdot 5=55.$$

\(20\)'ye kadar katkı veren diğer asallar \(3,5,13,19\)'dur ve katkıları sırasıyla \(9,10,26,19\)'dur. Buna karşılık \(17\) katkı yapmaz; çünkü tek çözüm sınıfı \(16\pmod{17}\) olup \(10\)'un altında yoktur. Böylece

$$S(10,20)=10+9+10+28+55+26+19=157.$$

Kodun Çalışma Mantığı

C++, Python ve Java uygulamaları aynı sayı kuramsal iskeleti izler. Önce \(M\)'ye kadar tüm asallar üretilir. Sonra her asal için \(d=\gcd(15,p-1)\) hesaplanır, mertebesi tam olarak \(d\) olan bir eleman bulunur, bundan \(x^{15}\equiv -1\pmod p\) denkleminin bütün çözüm sınıfları elde edilir ve her sınıf için \(1\le x\le N\) sayısı hesaplanıp \(p\) ile çarpılarak toplama eklenir.

C++ sürümünde ayrıca doğal bir paralellik vardır: asal katkıları birbirinden bağımsız olduğu için asal listesi parçalara ayrılıp ayrı iş parçacıklarında işlenebilir.

Karmaşıklık Analizi

Buradaki doğrudan elek yaklaşımıyla \(M\)'ye kadar asal üretimi \(O(M\log\log M)\) zaman ve \(O(M)\) bellek ister. Elekten sonra her asal için yapılan ek iş küçüktür: bir EBOB hesabı, mertebesi \(d\) olan bir eleman için kısa bir arama ve en fazla \(15\) artık sınıfının işlenmesi. Bu yüzden toplam çalışma süresi esas olarak asalları tarama maliyeti tarafından belirlenir; \(N\)'ye tek tek bakmak gerekmez.

Kaynaklar

  1. Problem sayfası: https://projecteuler.net/problem=421
  2. Modüler çarpımsal grup: Wikipedia — Çarpımsal grup
  3. Primitif kök: Wikipedia — Primitif kök
  4. Kongruensler ve modüler aritmetik: Wikipedia — Modüler aritmetik
  5. Eratosthenes eleği: Wikipedia — Eratosthenes eleği

Resumen del Problema

Definimos

$$f(x,M)=\sum_{\substack{p\le M\\ p\mid x^{15}+1}} p$$

y buscamos la suma total

$$S(N,M)=\sum_{x=1}^{N} f(x,M).$$

Con los parámetros reales no se puede recorrer cada \(x\) y comprobar todos los primos. La idea decisiva es reagrupar la suma por primos y contar solamente las clases residuales que satisfacen la congruencia correspondiente.

Enfoque Matemático

1. Invertir el orden de las sumas

Escribimos

$$S(N,M)=\sum_{p\le M} p\,A_p(N),$$

donde

$$A_p(N)=\left|\left\{1\le x\le N : x^{15}\equiv -1 \pmod p\right\}\right|.$$

Ahora el problema queda separado en contribuciones independientes de cada primo \(p\).

2. Número de soluciones de \(x^{15}\equiv -1 \pmod p\)

Para un primo impar, el grupo multiplicativo \((\mathbb{Z}/p\mathbb{Z})^\times\) es cíclico de orden \(p-1\). Si \(g\) es un generador y \(x=g^k\), entonces \(-1=g^{(p-1)/2}\), así que la congruencia se transforma en

$$15k\equiv \frac{p-1}{2}\pmod{p-1}.$$

Una congruencia lineal \(ak\equiv b\pmod m\) tiene solución si y solo si \(\gcd(a,m)\mid b\), y en ese caso tiene exactamente \(\gcd(a,m)\) clases solución. Por tanto, el número de residuos válidos es

$$d_p=\gcd(15,p-1).$$

Esto siempre funciona para \(p\) impar porque \(d_p\) es un divisor impar de \(15\), luego también es un divisor impar de \(p-1\), y todo divisor impar de \(p-1\) divide a \((p-1)/2\). El caso \(p=2\) también encaja: \(d_2=\gcd(15,1)=1\), con única solución \(x\equiv 1\pmod 2\).

3. Generar todas las clases solución

Como \((-1)^{15}=-1\), ya conocemos una solución. Las demás se obtienen multiplicando por raíces 15-ésimas de la unidad. El subgrupo

$$U_p=\left\{u\in (\mathbb{Z}/p\mathbb{Z})^\times : u^{15}\equiv 1\pmod p\right\}$$

tiene exactamente \(d_p\) elementos. Si \(r\) tiene orden exacto \(d_p\), entonces

$$U_p=\{r^0,r^1,\dots,r^{d_p-1}\},$$

y las soluciones de nuestra congruencia son

$$h_j\equiv -r^j\pmod p,\qquad 0\le j<d_p.$$

Eso es justo lo que hace la implementación: encuentra un elemento de orden \(d_p\) y recorre una sola órbita geométrica. Como \(d_p\in\{1,3,5,15\}\), cada primo aporta a lo sumo 15 clases residuales.

4. Contar cuántos enteros hasta \(N\) caen en una clase

Si \(1\le h\le p-1\), los números con \(x\equiv h\pmod p\) son

$$h,\ h+p,\ h+2p,\ \dots,$$

por lo que su cantidad es

$$\left\lfloor\frac{N-h}{p}\right\rfloor+1=\left\lfloor\frac{N+p-h}{p}\right\rfloor.$$

Cuando \(h>N\), esta misma expresión produce \(0\). En consecuencia, la contribución de un primo es

$$C_p(N)=p\sum_{j=0}^{d_p-1}\left\lfloor\frac{N+p-h_j}{p}\right\rfloor,$$

y el resultado final queda

$$\boxed{S(N,M)=\sum_{p\le M} p\sum_{j=0}^{d_p-1}\left\lfloor\frac{N+p-h_j}{p}\right\rfloor.}$$

5. Ejemplo trabajado: \(N=10,\ M=20\)

Para \(p=2\), la única clase es \(h=1\). Hay \(5\) números impares hasta \(10\), así que \(C_2=10\).

Para \(p=7\), \(d_7=\gcd(15,6)=3\). Tomando \(r=4\) de orden \(3\), se obtienen las clases \(h\in\{3,5,6\}\). En \(1,\dots,10\) aparecen \(2,1,1\) veces, de modo que

$$C_7=7(2+1+1)=28.$$

Para \(p=11\), \(d_{11}=5\) y las clases son \(h\in\{7,6,2,8,10\}\). Cada una aparece una vez, luego

$$C_{11}=11\cdot 5=55.$$

Los otros primos que contribuyen hasta \(20\) son \(3,5,13,19\), con aportes \(9,10,26,19\). En cambio, \(17\) no contribuye porque su única clase solución es \(16\pmod{17}\), ausente por debajo de \(10\). Por tanto,

$$S(10,20)=10+9+10+28+55+26+19=157.$$

Cómo Funciona la Implementación

Las implementaciones en C++, Python y Java siguen exactamente este esquema. Primero generan todos los primos hasta \(M\). Después, para cada primo, calculan \(d=\gcd(15,p-1)\), construyen un elemento de orden exacto \(d\), enumeran las \(d\) clases solución de \(x^{15}\equiv -1\pmod p\) y suman \(p\) multiplicado por el número de enteros hasta \(N\) en cada clase.

La versión en C++ además puede dividir la lista de primos en bloques independientes, porque la contribución de cada primo se acumula de forma aditiva y no depende de las demás.

Análisis de Complejidad

La criba hasta \(M\) cuesta \(O(M\log\log M)\) tiempo y \(O(M)\) memoria en la forma directa utilizada aquí. Después, el trabajo extra por primo es pequeño: un gcd, una búsqueda corta de un elemento de orden \(d\) y el procesamiento de solo \(d\le 15\) clases residuales. Por eso el coste real queda dominado por el barrido de primos y no por \(N\).

Referencias

  1. Página del problema: https://projecteuler.net/problem=421
  2. Grupo multiplicativo módulo \(n\): Wikipedia — Grupo multiplicativo de los enteros módulo \(n\)
  3. Raíz primitiva: Wikipedia — Raíz primitiva módulo \(n\)
  4. Congruencias lineales: Wikipedia — Congruencia aritmética
  5. Criba de Eratóstenes: Wikipedia — Criba de Eratóstenes

问题概述

先定义

$$f(x,M)=\sum_{\substack{p\le M\\ p\mid x^{15}+1}} p,$$

目标总和为

$$S(N,M)=\sum_{x=1}^{N} f(x,M).$$

当 \(N\) 和 \(M\) 很大时,逐个检查每个 \(x\) 是否被每个素数整除完全不可行。真正有效的做法是按素数重新组织求和,并把问题变成“某个模 \(p\) 的解类在 \(1\) 到 \(N\) 中出现多少次”。

数学方法

1. 交换求和顺序

把外层改为按素数求和:

$$S(N,M)=\sum_{p\le M} p\,A_p(N),$$

其中

$$A_p(N)=\left|\left\{1\le x\le N : x^{15}\equiv -1 \pmod p\right\}\right|.$$

于是每个素数 \(p\) 的贡献都可以独立处理。

2. 求解 \(x^{15}\equiv -1 \pmod p\) 的解数

对奇素数 \(p\),乘法群 \((\mathbb{Z}/p\mathbb{Z})^\times\) 是阶为 \(p-1\) 的循环群。若取一个生成元 \(g\),并写 \(x=g^k\),那么因为 \(-1=g^{(p-1)/2}\),原方程变成

$$15k\equiv \frac{p-1}{2}\pmod{p-1}.$$

线性同余 \(ak\equiv b\pmod m\) 有解当且仅当 \(\gcd(a,m)\mid b\),并且在有解时恰好有 \(\gcd(a,m)\) 个不同解类。因此这里的解数是

$$d_p=\gcd(15,p-1).$$

这对奇素数总是成立,因为 \(d_p\) 是 15 的奇因子,也是 \(p-1\) 的奇因子,所以必然整除 \((p-1)/2\)。特殊情形 \(p=2\) 也兼容同一公式:\(d_2=\gcd(15,1)=1\),唯一解是 \(x\equiv 1\pmod 2\)。

3. 显式写出全部解类

由于 \((-1)^{15}=-1\),所以 \(-1\) 本身就是一个解。其他解都可以看成它乘上一个 15 次单位根。子群

$$U_p=\left\{u\in (\mathbb{Z}/p\mathbb{Z})^\times : u^{15}\equiv 1\pmod p\right\}$$

恰有 \(d_p\) 个元素。如果 \(r\) 的阶正好是 \(d_p\),那么

$$U_p=\{r^0,r^1,\dots,r^{d_p-1}\},$$

所以原方程的全部解可以写成

$$h_j\equiv -r^j\pmod p,\qquad 0\le j<d_p.$$

实现就是按这个结构做的:先找一个阶为 \(d_p\) 的元素,再沿着这个几何循环走一圈。因为 \(d_p\in\{1,3,5,15\}\),所以每个素数最多只需要处理 15 个剩余类。

4. 统计一个剩余类在 \(1\) 到 \(N\) 中出现多少次

若 \(1\le h\le p-1\),满足 \(x\equiv h\pmod p\) 的正整数依次是

$$h,\ h+p,\ h+2p,\ \dots,$$

因此其个数为

$$\left\lfloor\frac{N-h}{p}\right\rfloor+1=\left\lfloor\frac{N+p-h}{p}\right\rfloor.$$

当 \(h>N\) 时,这个公式自然给出 \(0\)。于是素数 \(p\) 的贡献为

$$C_p(N)=p\sum_{j=0}^{d_p-1}\left\lfloor\frac{N+p-h_j}{p}\right\rfloor,$$

总公式就是

$$\boxed{S(N,M)=\sum_{p\le M} p\sum_{j=0}^{d_p-1}\left\lfloor\frac{N+p-h_j}{p}\right\rfloor.}$$

5. 例子:\(N=10,\ M=20\)

当 \(p=2\) 时,唯一解类是 \(h=1\)。在 \(1\) 到 \(10\) 中共有 5 个奇数,所以 \(C_2=10\)。

当 \(p=7\) 时,\(d_7=\gcd(15,6)=3\)。取一个阶为 3 的元素 \(r=4\),得到解类 \(h\in\{3,5,6\}\)。它们在 \(1,\dots,10\) 中分别出现 \(2,1,1\) 次,因此

$$C_7=7(2+1+1)=28.$$

当 \(p=11\) 时,\(d_{11}=5\),五个解类为 \(h\in\{7,6,2,8,10\}\)。它们各出现一次,所以

$$C_{11}=11\cdot 5=55.$$

不超过 20 的其他贡献素数还有 \(3,5,13,19\),对应贡献为 \(9,10,26,19\)。而 \(17\) 的唯一解类是 \(16\pmod{17}\),在 10 以下没有出现,因此贡献为 0。于是

$$S(10,20)=10+9+10+28+55+26+19=157.$$

实现说明

C++、Python 和 Java 实现都遵循同一条数学路线。先筛出所有不超过 \(M\) 的素数;然后对每个素数计算 \(d=\gcd(15,p-1)\),寻找一个阶恰为 \(d\) 的元素,枚举方程 \(x^{15}\equiv -1\pmod p\) 的全部 \(d\) 个解类,再把每个解类在 \(1\) 到 \(N\) 中的出现次数乘上 \(p\) 加入总和。

C++ 版本还利用了额外的并行性:不同素数的贡献彼此独立,所以可以把素数表切成若干段分别处理,再把部分和相加。

复杂度分析

直接筛法生成不超过 \(M\) 的素数需要 \(O(M\log\log M)\) 时间和 \(O(M)\) 内存。筛完以后,每个素数只需做很少的工作:一次 gcd、一次很短的阶搜索,以及最多 \(15\) 个解类的计数。因此总体运行时间主要由筛素数决定,而不再取决于 \(N\) 的巨大规模。

参考资料

  1. 题目页面:https://projecteuler.net/problem=421
  2. 模 \(n\) 的乘法群:Wikipedia — 乘法群
  3. 原根:Wikipedia — 原根
  4. 同余与线性同余:Wikipedia — 同余
  5. 埃拉托斯特尼筛法:Wikipedia — 埃拉托斯特尼筛法

Краткое описание задачи

Введём функцию

$$f(x,M)=\sum_{\substack{p\le M\\ p\mid x^{15}+1}} p$$

и суммарную величину

$$S(N,M)=\sum_{x=1}^{N} f(x,M).$$

При больших \(N\) и \(M\) прямой перебор невозможен. Нужно не проверять каждое \(x\), а считать вклад каждого простого числа через классы вычетов по модулю этого простого.

Математический подход

1. Перестановка порядка суммирования

Перепишем сумму в виде

$$S(N,M)=\sum_{p\le M} p\,A_p(N),$$

где

$$A_p(N)=\left|\left\{1\le x\le N : x^{15}\equiv -1 \pmod p\right\}\right|.$$

Теперь задача раскладывается на независимые вклады отдельных простых \(p\).

2. Сколько решений имеет \(x^{15}\equiv -1 \pmod p\)

Для нечётного простого \(p\) группа \((\mathbb{Z}/p\mathbb{Z})^\times\) циклическая и имеет порядок \(p-1\). Пусть \(g\) — её образующий элемент, \(x=g^k\). Тогда \(-1=g^{(p-1)/2}\), и исходное сравнение превращается в

$$15k\equiv \frac{p-1}{2}\pmod{p-1}.$$

Линейное сравнение \(ak\equiv b\pmod m\) разрешимо тогда и только тогда, когда \(\gcd(a,m)\mid b\), а число решений равно \(\gcd(a,m)\). Значит, количество подходящих классов равно

$$d_p=\gcd(15,p-1).$$

Для нечётного \(p\) условие разрешимости выполнено автоматически: \(d_p\) — нечётный делитель числа \(15\), следовательно, нечётный делитель \(p-1\), а любой нечётный делитель \(p-1\) делит и \((p-1)/2\). Случай \(p=2\) также согласуется с формулой: \(d_2=\gcd(15,1)=1\), единственный класс — \(x\equiv 1\pmod 2\).

3. Явное описание всех классов решений

Так как \((-1)^{15}=-1\), число \(-1\) само является решением. Все остальные решения получаются умножением на 15-е корни из единицы. Подгруппа

$$U_p=\left\{u\in (\mathbb{Z}/p\mathbb{Z})^\times : u^{15}\equiv 1\pmod p\right\}$$

содержит ровно \(d_p\) элементов. Если \(r\) имеет точный порядок \(d_p\), то

$$U_p=\{r^0,r^1,\dots,r^{d_p-1}\},$$

а все решения задаются формулой

$$h_j\equiv -r^j\pmod p,\qquad 0\le j<d_p.$$

Именно это и делает реализация: находит один элемент нужного порядка и проходит по всей геометрической орбите. Поскольку \(d_p\in\{1,3,5,15\}\), для каждого простого требуется рассмотреть не более 15 классов вычетов.

4. Подсчёт чисел до \(N\) в одном классе вычетов

Если \(1\le h\le p-1\), то числа с условием \(x\equiv h\pmod p\) имеют вид

$$h,\ h+p,\ h+2p,\ \dots,$$

поэтому их количество равно

$$\left\lfloor\frac{N-h}{p}\right\rfloor+1=\left\lfloor\frac{N+p-h}{p}\right\rfloor.$$

Если \(h>N\), та же формула даёт \(0\). Следовательно, вклад одного простого равен

$$C_p(N)=p\sum_{j=0}^{d_p-1}\left\lfloor\frac{N+p-h_j}{p}\right\rfloor,$$

и окончательная формула имеет вид

$$\boxed{S(N,M)=\sum_{p\le M} p\sum_{j=0}^{d_p-1}\left\lfloor\frac{N+p-h_j}{p}\right\rfloor.}$$

5. Разобранный пример: \(N=10,\ M=20\)

Для \(p=2\) единственный класс — \(h=1\). До \(10\) есть 5 нечётных чисел, значит \(C_2=10\).

Для \(p=7\) получаем \(d_7=\gcd(15,6)=3\). Если взять элемент \(r=4\) порядка 3, то решениями будут классы \(h\in\{3,5,6\}\). В диапазоне \(1,\dots,10\) они встречаются \(2,1,1\) раз, поэтому

$$C_7=7(2+1+1)=28.$$

Для \(p=11\) имеем \(d_{11}=5\), а классы решений равны \(h\in\{7,6,2,8,10\}\). Каждый из них встречается ровно один раз, так что

$$C_{11}=11\cdot 5=55.$$

Остальные простые до \(20\), которые дают вклад, это \(3,5,13,19\) с вкладами \(9,10,26,19\). Простое \(17\) даёт ноль, потому что его единственный класс решений — \(16\pmod{17}\), а ниже \(10\) таких чисел нет. Итак,

$$S(10,20)=10+9+10+28+55+26+19=157.$$

Как Работает Реализация

Реализации на C++, Python и Java следуют одной и той же схеме. Сначала строится список всех простых \(p\le M\). Затем для каждого простого вычисляется \(d=\gcd(15,p-1)\), находится элемент точного порядка \(d\), перечисляются все \(d\) решения сравнения \(x^{15}\equiv -1\pmod p\), и к ответу прибавляется \(p\), умноженное на число вхождений каждого класса вычетов среди чисел от \(1\) до \(N\).

Версия на C++ дополнительно использует параллелизм: вклад разных простых независим, поэтому список простых можно разделить на блоки и обрабатывать параллельно с последующим суммированием частичных результатов.

Анализ Сложности

Решето до \(M\) требует \(O(M\log\log M)\) времени и \(O(M)\) памяти в прямой реализации, используемой здесь. После этого работа на один простой мала: один gcd, короткий поиск элемента нужного порядка и обработка не более чем \(15\) классов вычетов. Поэтому общая сложность определяется главным образом генерацией и проходом по простым, а не величиной \(N\).

Источники

  1. Страница задачи: https://projecteuler.net/problem=421
  2. Мультипликативная группа по модулю: Wikipedia — Мультипликативная группа кольца вычетов
  3. Первообразный корень: Wikipedia — Первообразный корень
  4. Сравнения по модулю: Wikipedia — Сравнение по модулю
  5. Решето Эратосфена: Wikipedia — Решето Эратосфена

ملخص المسألة

نعرّف أولاً

$$f(x,M)=\sum_{\substack{p\le M\\ p\mid x^{15}+1}} p$$

ثم نريد حساب المجموع الكلي

$$S(N,M)=\sum_{x=1}^{N} f(x,M).$$

عندما تكون القيم كبيرة جداً لا يمكن فحص كل \(x\) مباشرة. الفكرة الأساسية هي إعادة ترتيب الجمع بحسب الأعداد الأولية، ثم عدّ أصناف البواقي التي تحقق \(x^{15}\equiv -1\pmod p\) لكل أولي على حدة.

المنهج الرياضي

1. تبديل ترتيب الجمع

نكتب

$$S(N,M)=\sum_{p\le M} p\,A_p(N),$$

حيث

$$A_p(N)=\left|\left\{1\le x\le N : x^{15}\equiv -1 \pmod p\right\}\right|.$$

وبذلك يتحول المطلوب إلى حساب مساهمة كل أولي \(p\) بشكل مستقل.

2. عدد حلول \(x^{15}\equiv -1 \pmod p\)

إذا كان \(p\) أولياً فردياً فإن المجموعة الضربية \((\mathbb{Z}/p\mathbb{Z})^\times\) دورية ورتبتها \(p-1\). إذا أخذنا مولداً \(g\) وكتبنا \(x=g^k\)، فإن \(-1=g^{(p-1)/2}\)، فتتحول المعادلة إلى

$$15k\equiv \frac{p-1}{2}\pmod{p-1}.$$

والمطابقة الخطية \(ak\equiv b\pmod m\) تملك حلولاً إذا وفقط إذا كان \(\gcd(a,m)\mid b\)، وعندئذ يكون عدد أصناف الحلول مساوياً لـ \(\gcd(a,m)\). لذلك يكون عدد الحلول هنا

$$d_p=\gcd(15,p-1).$$

وهذا الشرط متحقق دائماً للأولي الفردي، لأن \(d_p\) قاسم فردي للعدد 15، وبالتالي هو قاسم فردي لـ \(p-1\)، وكل قاسم فردي لـ \(p-1\) يقسم أيضاً \((p-1)/2\). أما الحالة \(p=2\) فتنسجم مع الصيغة نفسها: \(d_2=\gcd(15,1)=1\)، والحل الوحيد هو \(x\equiv 1\pmod 2\).

3. وصف جميع أصناف الحلول

بما أن \((-1)^{15}=-1\)، فإن \(-1\) نفسه حل. وكل حل آخر يُستخرج بضربه في جذر خامس عشر للوحدة. الزمرة الجزئية

$$U_p=\left\{u\in (\mathbb{Z}/p\mathbb{Z})^\times : u^{15}\equiv 1\pmod p\right\}$$

عدد عناصرها يساوي تماماً \(d_p\). فإذا أخذنا عنصراً \(r\) رتبته الدقيقة \(d_p\)، نحصل على

$$U_p=\{r^0,r^1,\dots,r^{d_p-1}\},$$

ومن ثم تكون جميع الحلول

$$h_j\equiv -r^j\pmod p,\qquad 0\le j<d_p.$$

هذا هو البناء المستخدم في التنفيذات: يتم العثور على عنصر من الرتبة \(d_p\)، ثم المرور مرة واحدة على الدورة الناتجة. وبما أن \(d_p\in\{1,3,5,15\}\)، فلا يزيد عدد أصناف البواقي المطلوبة لكل أولي على 15.

4. عدّ الأعداد حتى \(N\) داخل صنف باق واحد

إذا كان \(1\le h\le p-1\)، فإن الأعداد التي تحقق \(x\equiv h\pmod p\) هي

$$h,\ h+p,\ h+2p,\ \dots,$$

ولذلك يكون عددها

$$\left\lfloor\frac{N-h}{p}\right\rfloor+1=\left\lfloor\frac{N+p-h}{p}\right\rfloor.$$

وعندما يكون \(h>N\) تعطي الصيغة نفسها القيمة \(0\). إذن مساهمة الأولي \(p\) هي

$$C_p(N)=p\sum_{j=0}^{d_p-1}\left\lfloor\frac{N+p-h_j}{p}\right\rfloor,$$

والنتيجة النهائية تصبح

$$\boxed{S(N,M)=\sum_{p\le M} p\sum_{j=0}^{d_p-1}\left\lfloor\frac{N+p-h_j}{p}\right\rfloor.}$$

5. مثال محلول: \(N=10,\ M=20\)

عند \(p=2\) يكون الصنف الوحيد هو \(h=1\). يوجد خمسة أعداد فردية حتى 10، ولذلك \(C_2=10\).

وعند \(p=7\) نجد أن \(d_7=\gcd(15,6)=3\). إذا اخترنا \(r=4\) من الرتبة 3 فإن أصناف الحلول هي \(h\in\{3,5,6\}\). وتظهر هذه الأصناف داخل \(1,\dots,10\) بالأعداد \(2,1,1\) على الترتيب، ومن ثم

$$C_7=7(2+1+1)=28.$$

وعند \(p=11\) يكون \(d_{11}=5\)، وأصناف الحلول هي \(h\in\{7,6,2,8,10\}\). وكل واحد منها يظهر مرة واحدة، لذلك

$$C_{11}=11\cdot 5=55.$$

أما الأوليات الأخرى التي تعطي مساهمة حتى 20 فهي \(3,5,13,19\) وقيم مساهماتها \(9,10,26,19\). بينما لا يعطي \(17\) أي مساهمة، لأن صنف الحل الوحيد هو \(16\pmod{17}\) ولا يظهر تحت 10. وبالتالي

$$S(10,20)=10+9+10+28+55+26+19=157.$$

كيف تعمل التنفيذات

تنفيذات C++ وPython وJava تتبع الخطة العددية نفسها. أولاً يتم توليد جميع الأعداد الأولية حتى \(M\). ثم لكل أولي يُحسب \(d=\gcd(15,p-1)\)، ويُبنى عنصر رتبته الدقيقة \(d\)، وتُولد منه جميع أصناف الحلول للمعادلة \(x^{15}\equiv -1\pmod p\)، ثم يضاف إلى المجموع \(p\) مضروباً في عدد مرات ظهور كل صنف بين \(1\) و\(N\).

وفي نسخة C++ توجد فائدة إضافية هي سهولة التوازي: مساهمات الأوليات مستقلة تماماً، لذا يمكن تقسيم قائمة الأوليات إلى أجزاء ومعالجة كل جزء على حدة ثم جمع النتائج الجزئية.

تحليل التعقيد

توليد جميع الأوليات حتى \(M\) بالغربال المباشر يكلف \(O(M\log\log M)\) زمناً و\(O(M)\) ذاكرة. بعد ذلك يصبح العمل لكل أولي صغيراً: حساب gcd واحد، وبحث قصير عن عنصر من الرتبة \(d\)، ثم معالجة عدد لا يتجاوز \(15\) من أصناف البواقي. لذلك فإن الكلفة الإجمالية تهيمن عليها عملية المرور على الأوليات، لا المرور على القيم حتى \(N\).

مراجع

  1. صفحة المسألة: https://projecteuler.net/problem=421
  2. الزمرة الضربية بترديد \(n\): Wikipedia — زمرة ضربية
  3. الجذر البدائي: Wikipedia — جذر بدائي
  4. الحسابيات التوافقية: Wikipedia — حسابيات توافقية
  5. غربال إراتوستينس: Wikipedia — غربال إراتوستينس