Problem Summary

For every prime \(p\neq2,5\), define the decimal divisibility multiplier \(m(p)\) as the number that lets us replace a divisibility test on

$$n=10q+r$$

by a test on the shorter number \(q+m(p)r\). The problem asks for the sum of these multipliers over all primes below a large limit. The final numeric answer is omitted here; what matters is the mathematical reason this multiplier exists and why the code computes it so quickly.

Mathematical Approach

1) Why primes \(2\) and \(5\) are excluded

Any decimal integer can be split into quotient and last digit as

$$n=10q+r,\qquad 0\le r\le 9.$$

If \(p=2\) or \(p=5\), then \(10\equiv0\pmod p\), so \(10\) has no multiplicative inverse modulo \(p\). That means the whole “remove the last digit and adjust” trick cannot be expressed by multiplying with \(10^{-1}\).

For every other prime \(p\), we have \(\gcd(10,p)=1\), so a unique inverse of \(10\) exists modulo \(p\).

2) Deriving the multiplier formula

Start from the divisibility condition

$$p\mid n \iff p\mid (10q+r).$$

Let \(t\) be the modular inverse of \(10\), so

$$10t\equiv1\pmod p.$$

Multiply the congruence \(10q+r\equiv0\pmod p\) by \(t\):

$$q+tr\equiv0\pmod p.$$

Therefore

$$p\mid n \iff p\mid (q+tr).$$

So the divisibility multiplier is exactly

$$\boxed{m(p)\equiv10^{-1}\pmod p.}$$

The code returns the least nonnegative representative of this inverse.

3) Relation to the familiar “subtract the last digit” tests

Sometimes schoolbook divisibility rules are written with subtraction instead of addition. That is the same thing, because if \(m(p)\) is the inverse of \(10\), then \(m(p)-p\) is an equivalent multiplier modulo \(p\).

For example, for \(p=7\) we have

$$10^{-1}\equiv5\pmod7,$$

so one valid rule is

$$7\mid(10q+r)\iff 7\mid(q+5r).$$

But since \(5\equiv-2\pmod7\), this is the usual rule

$$7\mid(10q+r)\iff 7\mid(q-2r).$$

The Project Euler problem chooses the positive modular inverse.

4) Worked example: \(p=13\)

Because \(10\cdot4=40\equiv1\pmod{13}\), we have

$$m(13)=4.$$

So

$$13\mid(10q+r)\iff 13\mid(q+4r).$$

Apply that repeatedly to the divisible number \(3484\):

$$3484 \longrightarrow 348+4\cdot4=364,$$

$$364 \longrightarrow 36+4\cdot4=52,$$

$$52 \longrightarrow 5+4\cdot2=13.$$

Since \(13\) is divisible by \(13\), the original number is also divisible by \(13\). This shows why the multiplier rule is a genuine digit-stripping test, not just a single-step congruence trick.

5) Worked example: \(p=113\) and extended Euclid

The code contains the checkpoint \(m(113)=34\). Here is why. Run the Euclidean algorithm:

$$113=11\cdot10+3,\qquad 10=3\cdot3+1.$$

Now back-substitute:

$$1=10-3\cdot3=10-(113-11\cdot10)\cdot3=34\cdot10-3\cdot113.$$

Hence

$$10\cdot34\equiv1\pmod{113},$$

so

$$m(113)=34.$$

A quick check with \(791=7\cdot113\):

$$79+34\cdot1=113,$$

which is obviously divisible by \(113\), so the test works exactly as predicted.

6) Why the whole problem reduces to summing inverses

Once the derivation is done, nothing deeper remains: for each prime \(p\neq2,5\), the desired multiplier is simply \(10^{-1}\pmod p\). So the problem becomes

$$\sum_{\substack{p<L\\ p\ \text{prime}\\ p\neq2,5}} 10^{-1}\!\!\!\pmod p,$$

with the inverse interpreted as its least nonnegative representative.

How the Code Works

Prime generation. primes_up_to() uses a linear sieve to list all primes below prime_limit.

Inverse computation. inverse_mod_10(p) runs an iterative extended Euclidean algorithm on \(10\) and \(p\). The returned coefficient of \(10\) is reduced into the range \([0,p-1]\).

Accumulation. solve() skips \(2\) and \(5\), sums the inverses for all other primes, and returns a 64-bit total.

Checkpoints. The source verifies

$$m(113)=34,\qquad \text{solve}(1000)=39517.$$

It also exposes --prime-limit=... and --skip-checkpoints for controlled runs.

Complexity Analysis

With a linear sieve, generating primes up to \(L\) costs \(O(L)\) time and \(O(L)\) memory. For each prime, the extended Euclidean algorithm costs \(O(\log p)\), so the total post-sieve work is

$$O\!\left(\sum_{p<L}\log p\right)=O(\pi(L)\log L).$$

For the given limit this is easily fast enough, because the arithmetic per prime is tiny.

Further Reading

  1. Problem page: https://projecteuler.net/problem=274
  2. Modular multiplicative inverse: https://en.wikipedia.org/wiki/Modular_multiplicative_inverse
  3. Extended Euclidean algorithm: https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm
  4. Divisibility rules in base 10: https://en.wikipedia.org/wiki/Divisibility_rule

Problemzusammenfassung

Für jede Primzahl \(p\neq2,5\) wird ein Dezimal-Teilbarkeitsmultiplikator \(m(p)\) definiert. Er erlaubt, die Teilbarkeit einer Zahl

$$n=10q+r$$

durch eine kürzere Zahl \(q+m(p)r\) zu testen. Gesucht ist die Summe dieser Multiplikatoren für alle Primzahlen unter einer großen Schranke. Der Endwert ist hier nicht entscheidend; wichtig ist die Herleitung des Multiplikators und warum der Code ihn so direkt berechnet.

Mathematischer Ansatz

1) Warum \(2\) und \(5\) ausgeschlossen werden

Jede Dezimalzahl lässt sich als

$$n=10q+r,\qquad 0\le r\le 9$$

schreiben. Für \(p=2\) oder \(p=5\) gilt jedoch \(10\equiv0\pmod p\); also besitzt \(10\) kein multiplikatives Inverses modulo \(p\). Genau deshalb funktioniert die „letzte Ziffer abspalten und korrigieren“-Regel dort nicht in dieser Form.

Für jede andere Primzahl ist \(\gcd(10,p)=1\), also existiert \(10^{-1}\pmod p\).

2) Herleitung der Multiplikatorformel

Wir beginnen mit

$$p\mid n \iff p\mid(10q+r).$$

Sei \(t\) das Inverse von \(10\) modulo \(p\), also

$$10t\equiv1\pmod p.$$

Multipliziert man die Kongruenz \(10q+r\equiv0\pmod p\) mit \(t\), so erhält man

$$q+tr\equiv0\pmod p.$$

Damit folgt

$$p\mid n \iff p\mid(q+tr).$$

Der gesuchte Teilbarkeitsmultiplikator ist also exakt

$$\boxed{m(p)\equiv10^{-1}\pmod p.}$$

Der Code liefert den kleinsten nichtnegativen Repräsentanten dieses Inversen.

3) Zusammenhang mit den bekannten Regeln vom Typ „subtrahiere die letzte Ziffer“

Manche Teilbarkeitsregeln werden mit einem Minuszeichen formuliert. Das ist derselbe Inhalt, denn zu \(m(p)\) ist auch \(m(p)-p\) modulo \(p\) äquivalent.

Für \(p=7\) gilt zum Beispiel

$$10^{-1}\equiv5\pmod7,$$

also

$$7\mid(10q+r)\iff 7\mid(q+5r).$$

Da aber \(5\equiv-2\pmod7\), ist das dieselbe Regel wie

$$7\mid(10q+r)\iff 7\mid(q-2r).$$

Das Euler-Problem verwendet die positive Inverse.

4) Durchgerechnetes Beispiel: \(p=13\)

Da \(10\cdot4=40\equiv1\pmod{13}\), gilt

$$m(13)=4.$$

Also

$$13\mid(10q+r)\iff 13\mid(q+4r).$$

Auf die durch \(13\) teilbare Zahl \(3484\) angewandt:

$$3484 \longrightarrow 348+4\cdot4=364,$$

$$364 \longrightarrow 36+4\cdot4=52,$$

$$52 \longrightarrow 5+4\cdot2=13.$$

Da \(13\) durch \(13\) teilbar ist, war auch \(3484\) durch \(13\) teilbar. So sieht man, dass die Regel wiederholt angewandt wirklich die Zahl Stelle für Stelle verkürzt.

5) Beispiel \(p=113\) mit erweitertem Euklid

Der Code überprüft die Kontrollbedingung \(m(113)=34\). Herleitung mit Euklid:

$$113=11\cdot10+3,\qquad 10=3\cdot3+1.$$

Rückwärtseinsetzen liefert

$$1=10-3\cdot3=10-(113-11\cdot10)\cdot3=34\cdot10-3\cdot113.$$

Daher

$$10\cdot34\equiv1\pmod{113},$$

also

$$m(113)=34.$$

Kurzer Test mit \(791=7\cdot113\):

$$79+34\cdot1=113,$$

also bestätigt auch die Regel sofort die Teilbarkeit durch \(113\).

6) Warum das Gesamtproblem nur eine Inversensumme ist

Nach der Herleitung bleibt nichts weiter übrig: Für jede Primzahl \(p\neq2,5\) ist der gesuchte Multiplikator einfach \(10^{-1}\pmod p\). Das Problem reduziert sich also auf

$$\sum_{\substack{p<L\\ p\ \text{prim}\\ p\neq2,5}} 10^{-1}\!\!\!\pmod p,$$

wobei stets der kleinste nichtnegative Rest gemeint ist.

Wie der Code arbeitet

Primzahlerzeugung. primes_up_to() verwendet ein lineares Sieb und erzeugt alle Primzahlen unter prime_limit.

Inverse berechnen. inverse_mod_10(p) führt den erweiterten euklidischen Algorithmus für \(10\) und \(p\) iterativ aus. Der Koeffizient von \(10\) wird anschließend in den Bereich \([0,p-1]\) reduziert.

Aufsummieren. solve() überspringt \(2\) und \(5\), addiert für alle übrigen Primzahlen die Inversen und gibt die 64-Bit-Summe zurück.

Checkpoints. Die Quelle testet

$$m(113)=34,\qquad \text{solve}(1000)=39517.$$

Zusätzlich gibt es die Optionen --prime-limit=... und --skip-checkpoints.

Komplexitätsanalyse

Mit linearem Sieb kostet die Primzahlerzeugung bis \(L\) Zeit \(O(L)\) und Speicher \(O(L)\). Für jede Primzahl benötigt der erweiterte Euklid \(O(\log p)\), sodass der Zusatzaufwand nach dem Sieb

$$O\!\left(\sum_{p<L}\log p\right)=O(\pi(L)\log L)$$

beträgt. Für die gegebene Grenze ist das mehr als schnell genug.

Weiterführende Hinweise

  1. Problem: https://projecteuler.net/problem=274
  2. Multiplikativ inverses Element: https://de.wikipedia.org/wiki/Multiplikativ_inverses_Element
  3. Erweiterter euklidischer Algorithmus: https://de.wikipedia.org/wiki/Erweiterter_euklidischer_Algorithmus
  4. Teilbarkeitsregeln: https://de.wikipedia.org/wiki/Teilbarkeitsregel

Problem Özeti

Her \(p\neq2,5\) asalı için onluk bölünebilme çarpanı \(m(p)\) tanımlanır. Bu çarpan sayesinde

$$n=10q+r$$

biçimindeki bir sayının \(p\)'ye bölünebilirliği, daha kısa olan \(q+m(p)r\) sayısına indirgenebilir. Problem, büyük bir üst sınırın altındaki tüm asallar için bu çarpanları toplamayı ister. Burada önemli olan nihai cevap değil, çarpanın neden var olduğu ve kodun bunu neden çok hızlı hesaplayabildiğidir.

Matematiksel Yaklaşım

1) Neden \(2\) ve \(5\) dışarıda bırakılıyor

Her onluk sayı

$$n=10q+r,\qquad 0\le r\le 9$$

şeklinde yazılabilir. Eğer \(p=2\) veya \(p=5\) ise \(10\equiv0\pmod p\) olur; yani 10'un mod \(p\) çarpımsal tersi yoktur. Son basamağı atıp düzeltme yapan testin temel dayanağı bu ters olduğu için, aynı yaklaşım bu iki asal için çalışmaz.

Diğer her asal için \(\gcd(10,p)=1\) olduğundan \(10^{-1}\pmod p\) vardır.

2) Çarpan formülünün türetilmesi

Bölünebilme koşulundan başlayalım:

$$p\mid n \iff p\mid(10q+r).$$

\(t\), 10'un mod \(p\) tersi olsun:

$$10t\equiv1\pmod p.$$

\(10q+r\equiv0\pmod p\) denkliğini \(t\) ile çarparsak

$$q+tr\equiv0\pmod p$$

elde ederiz. Dolayısıyla

$$p\mid n \iff p\mid(q+tr).$$

Yani aranan bölünebilme çarpanı tam olarak

$$\boxed{m(p)\equiv10^{-1}\pmod p.}$$

Kod bu tersin en küçük negatif olmayan temsilcisini döndürür.

3) Bildiğimiz “son basamağı çıkar” testleriyle ilişkisi

Bazı okul tipi bölünebilme kuralları toplama yerine çıkarma ile yazılır. Bu aslında aynı şeydir; çünkü \(m(p)\) yerine \(m(p)-p\) de aynı modüler çarpandır.

Örneğin \(p=7\) için

$$10^{-1}\equiv5\pmod7,$$

dolayısıyla geçerli bir kural

$$7\mid(10q+r)\iff 7\mid(q+5r)$$

olur. Ama \(5\equiv-2\pmod7\) olduğundan bu bildiğimiz

$$7\mid(10q+r)\iff 7\mid(q-2r)$$

kuralıyla aynıdır. Project Euler sorusu pozitif modüler tersi kullanır.

4) Çalışan örnek: \(p=13\)

\(10\cdot4=40\equiv1\pmod{13}\) olduğundan

$$m(13)=4.$$

Yani

$$13\mid(10q+r)\iff 13\mid(q+4r).$$

Bunu \(13\)'e bölünebilen \(3484\) sayısına tekrar tekrar uygulayalım:

$$3484 \longrightarrow 348+4\cdot4=364,$$

$$364 \longrightarrow 36+4\cdot4=52,$$

$$52 \longrightarrow 5+4\cdot2=13.$$

Sonunda \(13\) kaldığı için ilk sayı da \(13\)'e bölünür. Bu örnek, kuralın sadece tek adımlık bir kongruans hilesi değil, gerçekten sağdan sola basamak küçülten bir test olduğunu gösterir.

5) \(p=113\) örneği ve genişletilmiş Öklid

Kod, \(m(113)=34\) kontrolünü yapar. Sebebi şudur:

$$113=11\cdot10+3,\qquad 10=3\cdot3+1.$$

Geri yerine koyarsak

$$1=10-3\cdot3=10-(113-11\cdot10)\cdot3=34\cdot10-3\cdot113.$$

Buradan

$$10\cdot34\equiv1\pmod{113}$$

çıkar; yani

$$m(113)=34.$$

Kısa bir kontrol için \(791=7\cdot113\) alınırsa

$$79+34\cdot1=113$$

elde edilir ve sonuç doğrudan \(113\)'e bölünür.

6) Tüm problemin neden ters toplamına indiği

Bu türetim yapıldıktan sonra geriye daha derin bir yapı kalmaz: her \(p\neq2,5\) asalı için istenen çarpan yalnızca \(10^{-1}\pmod p\) değeridir. Dolayısıyla problem

$$\sum_{\substack{p<L\\ p\ \text{asal}\\ p\neq2,5}} 10^{-1}\!\!\!\pmod p$$

toplamını hesaplama işine dönüşür; burada ters, en küçük negatif olmayan temsilci olarak alınır.

Kodun Çalışma Mantığı

Asal üretimi. primes_up_to(), prime_limit altındaki tüm asalları lineer elek ile üretir.

Ters hesabı. inverse_mod_10(p), 10 ile \(p\) üzerinde iteratif genişletilmiş Öklid çalıştırır. 10'un katsayısı en sonda \([0,p-1]\) aralığına normalize edilir.

Toplama. solve(), \(2\) ve \(5\)'i atlar, diğer asallar için bulunan tersleri toplayıp 64 bitlik sonucu döndürür.

Checkpoint'ler. Kaynak kod şu iki kontrolü yapar:

$$m(113)=34,\qquad \text{solve}(1000)=39517.$$

Ayrıca --prime-limit=... ve --skip-checkpoints seçenekleri vardır.

Karmaşıklık Analizi

Lineer elek ile \(L\)'ye kadar asal üretmek \(O(L)\) zaman ve \(O(L)\) bellek gerektirir. Her asal için genişletilmiş Öklid \(O(\log p)\) sürer; bu yüzden elekten sonraki toplam iş

$$O\!\left(\sum_{p<L}\log p\right)=O(\pi(L)\log L)$$

olur. Verilen sınır için bu rahatlıkla yeterlidir.

İleri Okuma

  1. Problem metni: https://projecteuler.net/problem=274
  2. Modüler çarpımsal ters: https://tr.wikipedia.org/wiki/Modüler_çarpımsal_ters
  3. Genişletilmiş Öklid algoritması: https://tr.wikipedia.org/wiki/Genişletilmiş_Öklid_algoritması
  4. Bölünebilme kuralları: https://tr.wikipedia.org/wiki/Bölünebilme_kuralları

Resumen del Problema

Para cada primo \(p\neq2,5\), se define un multiplicador decimal de divisibilidad \(m(p)\). Ese número permite sustituir la prueba de divisibilidad de

$$n=10q+r$$

por la de un número más corto, \(q+m(p)r\). El problema pide sumar dichos multiplicadores para todos los primos por debajo de un gran límite. El valor final no es lo importante aquí; lo esencial es entender por qué ese multiplicador existe y por qué el código se reduce a calcular inversos modulares.

Enfoque Matemático

1) Por qué se excluyen \(2\) y \(5\)

Cualquier entero decimal se escribe como

$$n=10q+r,\qquad 0\le r\le 9.$$

Si \(p=2\) o \(p=5\), entonces \(10\equiv0\pmod p\), de modo que \(10\) no tiene inverso modular. Por eso la regla de “quitar la última cifra y corregir” no puede formularse igual para esos dos primos.

Para cualquier otro primo, \(\gcd(10,p)=1\), así que existe \(10^{-1}\pmod p\).

2) Derivación de la fórmula del multiplicador

Partimos de

$$p\mid n \iff p\mid(10q+r).$$

Sea \(t\) el inverso modular de \(10\):

$$10t\equiv1\pmod p.$$

Multiplicando \(10q+r\equiv0\pmod p\) por \(t\), obtenemos

$$q+tr\equiv0\pmod p.$$

Por tanto,

$$p\mid n \iff p\mid(q+tr).$$

Luego el multiplicador buscado es exactamente

$$\boxed{m(p)\equiv10^{-1}\pmod p.}$$

El programa devuelve el representante no negativo más pequeño.

3) Relación con las reglas conocidas de “restar la última cifra”

Muchas reglas escolares usan resta en lugar de suma. Eso es equivalente, porque \(m(p)-p\) representa la misma clase modular que \(m(p)\).

Para \(p=7\), por ejemplo,

$$10^{-1}\equiv5\pmod7,$$

así que una regla válida es

$$7\mid(10q+r)\iff 7\mid(q+5r).$$

Como \(5\equiv-2\pmod7\), eso coincide con la regla habitual

$$7\mid(10q+r)\iff 7\mid(q-2r).$$

La formulación del problema usa el inverso positivo.

4) Ejemplo trabajado: \(p=13\)

Puesto que \(10\cdot4=40\equiv1\pmod{13}\), tenemos

$$m(13)=4.$$

Entonces

$$13\mid(10q+r)\iff 13\mid(q+4r).$$

Apliquemos la regla repetidamente a \(3484\):

$$3484 \longrightarrow 348+4\cdot4=364,$$

$$364 \longrightarrow 36+4\cdot4=52,$$

$$52 \longrightarrow 5+4\cdot2=13.$$

Como \(13\) es divisible por \(13\), el número original también lo es. Esto muestra que la regla realmente elimina cifras desde la derecha.

5) Ejemplo \(p=113\) con Euclides extendido

El código verifica que \(m(113)=34\). La razón es

$$113=11\cdot10+3,\qquad 10=3\cdot3+1.$$

Retrocediendo,

$$1=10-3\cdot3=10-(113-11\cdot10)\cdot3=34\cdot10-3\cdot113.$$

Por ello

$$10\cdot34\equiv1\pmod{113},$$

y así

$$m(113)=34.$$

Comprobación rápida con \(791=7\cdot113\):

$$79+34\cdot1=113,$$

que claramente es múltiplo de \(113\).

6) Por qué todo el problema se reduce a sumar inversos

Una vez hecha la derivación, ya no queda ninguna estructura oculta: para cada primo \(p\neq2,5\), el multiplicador pedido es simplemente \(10^{-1}\pmod p\). Por tanto, el problema se convierte en calcular

$$\sum_{\substack{p<L\\ p\ \text{primo}\\ p\neq2,5}} 10^{-1}\!\!\!\pmod p,$$

tomando siempre el representante no negativo más pequeño.

Cómo Funciona el Código

Generación de primos. primes_up_to() usa una criba lineal para enumerar todos los primos por debajo de prime_limit.

Cálculo del inverso. inverse_mod_10(p) aplica el algoritmo extendido de Euclides a \(10\) y \(p\), y luego normaliza el coeficiente de \(10\) al intervalo \([0,p-1]\).

Acumulación. solve() omite \(2\) y \(5\), suma los inversos de los demás primos y devuelve el total en 64 bits.

Puntos de control. El código comprueba

$$m(113)=34,\qquad \text{solve}(1000)=39517.$$

También admite --prime-limit=... y --skip-checkpoints.

Complejidad

Con una criba lineal, generar los primos hasta \(L\) cuesta \(O(L)\) tiempo y \(O(L)\) memoria. Para cada primo, el algoritmo extendido de Euclides cuesta \(O(\log p)\), así que el trabajo adicional es

$$O\!\left(\sum_{p<L}\log p\right)=O(\pi(L)\log L).$$

Eso es muy eficiente para el límite del problema.

Lecturas

  1. Problema: https://projecteuler.net/problem=274
  2. Inverso multiplicativo modular: https://es.wikipedia.org/wiki/Inverso_multiplicativo
  3. Algoritmo de Euclides extendido: https://es.wikipedia.org/wiki/Algoritmo_de_Euclides
  4. Reglas de divisibilidad: https://es.wikipedia.org/wiki/Regla_de_divisibilidad

问题概述

对每个素数 \(p\neq2,5\),定义十进制整除乘子 \(m(p)\)。它的作用是把

$$n=10q+r$$

的整除判定,改写成更短数字 \(q+m(p)r\) 的整除判定。题目要求把某个大上界以下所有素数对应的乘子求和。这里不强调最 终数值,而是说明这个乘子为什么存在,以及代码为什么只需要求模逆元。

数学方法

1) 为什么要排除 \(2\) 和 \(5\)

任意十进制整数都可写成

$$n=10q+r,\qquad 0\le r\le 9.$$

如果 \(p=2\) 或 \(p=5\),那么 \(10\equiv0\pmod p\),所以 \(10\) 在模 \(p\) 下没有乘法逆元。因此“去掉最后一位再修正” 这类规则不能用同样的逆元推导来表达。

对其他任意素数,都有 \(\gcd(10,p)=1\),于是 \(10^{-1}\pmod p\) 存在。

2) 乘子公式的推导

从整除条件开始:

$$p\mid n \iff p\mid(10q+r).$$

设 \(t\) 是 \(10\) 在模 \(p\) 下的逆元,即

$$10t\equiv1\pmod p.$$

把 \(10q+r\equiv0\pmod p\) 两边乘上 \(t\),得到

$$q+tr\equiv0\pmod p.$$

因此

$$p\mid n \iff p\mid(q+tr).$$

所以所求乘子正是

$$\boxed{m(p)\equiv10^{-1}\pmod p.}$$

代码返回的是这个逆元在 \([0,p-1]\) 中的最小非负代表。

3) 它与常见“减去末位数字”规则的关系

很多学校里的整除规则写成减法形式,其实完全等价,因为 \(m(p)-p\) 与 \(m(p)\) 表示同一个模类。

例如对 \(p=7\),有

$$10^{-1}\equiv5\pmod7,$$

因此可以写成

$$7\mid(10q+r)\iff 7\mid(q+5r).$$

但由于 \(5\equiv-2\pmod7\),这与熟悉的规则

$$7\mid(10q+r)\iff 7\mid(q-2r)$$

完全一样。Project Euler 这里采用正的模逆。

4) 例子:\(p=13\)

因为 \(10\cdot4=40\equiv1\pmod{13}\),所以

$$m(13)=4.$$

于是

$$13\mid(10q+r)\iff 13\mid(q+4r).$$

把它反复应用到 \(3484\):

$$3484 \longrightarrow 348+4\cdot4=364,$$

$$364 \longrightarrow 36+4\cdot4=52,$$

$$52 \longrightarrow 5+4\cdot2=13.$$

最后得到 \(13\),显然可被 \(13\) 整除,所以原数也可被 \(13\) 整除。这说明该乘子规则确实可以不断剥去最后一位数字。

5) 例子:\(p=113\) 与扩展欧几里得

代码中的检查点之一是 \(m(113)=34\)。推导如下:

$$113=11\cdot10+3,\qquad 10=3\cdot3+1.$$

回代可得

$$1=10-3\cdot3=10-(113-11\cdot10)\cdot3=34\cdot10-3\cdot113.$$

因此

$$10\cdot34\equiv1\pmod{113},$$

从而

$$m(113)=34.$$

再看 \(791=7\cdot113\):

$$79+34\cdot1=113,$$

立刻得到一个明显可被 \(113\) 整除的数。

6) 为什么整个问题本质上就是“求逆元后求和”

推导完成后,问题已经没有别的隐藏结构:对每个 \(p\neq2,5\),所求乘子就是 \(10^{-1}\pmod p\)。因此目标等价于

$$\sum_{\substack{p<L\\ p\ \text{是素数}\\ p\neq2,5}} 10^{-1}\!\!\!\pmod p,$$

其中逆元始终取最小非负代表。

代码如何工作

素数筛。 primes_up_to() 用线性筛生成所有小于 prime_limit 的素数。

逆元计算。 inverse_mod_10(p) 对 \(10\) 和 \(p\) 运行迭代版扩展欧几里得算法,并把得到的 \(10\) 的系数归一化到 \([0,p-1]\)。

累加。 solve() 跳过 \(2\) 和 \(5\),对其余所有素数求逆元并累加到 64 位答案中。

检查点。 源码验证

$$m(113)=34,\qquad \text{solve}(1000)=39517.$$

同时支持 --prime-limit=...--skip-checkpoints

复杂度分析

线性筛生成到 \(L\) 的素数需要 \(O(L)\) 时间和 \(O(L)\) 内存。对每个素数,扩展欧几里得算法耗时 \(O(\log p)\),因此筛后额外工作量为

$$O\!\left(\sum_{p<L}\log p\right)=O(\pi(L)\log L).$$

对题目给定的规模,这个复杂度完全足够。

延伸阅读

  1. 题目页面: https://projecteuler.net/problem=274
  2. 模逆元: https://zh.wikipedia.org/wiki/模逆元
  3. 扩展欧几里得算法: https://zh.wikipedia.org/wiki/欧几里得算法
  4. 整除规则: https://zh.wikipedia.org/wiki/整除规则

Краткое описание

Для каждого простого \(p\neq2,5\) вводится десятичный множитель делимости \(m(p)\). С его помощью проверку делимости числа

$$n=10q+r$$

можно заменить проверкой более короткого числа \(q+m(p)r\). Задача просит просуммировать такие множители по всем простым ниже большого предела. Важно не столько само итоговое число, сколько понимание того, почему множитель существует и почему код фактически сводится к вычислению обратного элемента к \(10\) по модулю \(p\).

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

1) Почему исключаются \(2\) и \(5\)

Любое десятичное число представимо в виде

$$n=10q+r,\qquad 0\le r\le 9.$$

Если \(p=2\) или \(p=5\), то \(10\equiv0\pmod p\), а значит, у числа \(10\) нет обратного по модулю \(p\). Поэтому стандартный приём «отбросить последнюю цифру и скорректировать остаток» нельзя вывести тем же способом.

Для любой другой простой \(p\) имеем \(\gcd(10,p)=1\), поэтому \(10^{-1}\pmod p\) существует.

2) Вывод формулы для множителя

Начинаем с условия делимости:

$$p\mid n \iff p\mid(10q+r).$$

Пусть \(t\) — обратный элемент к \(10\) по модулю \(p\), то есть

$$10t\equiv1\pmod p.$$

Умножая сравнение \(10q+r\equiv0\pmod p\) на \(t\), получаем

$$q+tr\equiv0\pmod p.$$

Следовательно,

$$p\mid n \iff p\mid(q+tr).$$

Значит, искомый множитель равен

$$\boxed{m(p)\equiv10^{-1}\pmod p.}$$

Код берёт наименьший неотрицательный представитель этого класса.

3) Связь со школьными правилами вида «вычти последнюю цифру»

Во многих правилах делимости фигурирует вычитание, а не сложение. Это эквивалентно, потому что \(m(p)-p\) задаёт тот же остаток, что и \(m(p)\).

Например, для \(p=7\)

$$10^{-1}\equiv5\pmod7,$$

поэтому корректное правило имеет вид

$$7\mid(10q+r)\iff 7\mid(q+5r).$$

Но \(5\equiv-2\pmod7\), так что это та же самая привычная проверка

$$7\mid(10q+r)\iff 7\mid(q-2r).$$

В задаче используется положительный модульный обратный.

4) Подробный пример: \(p=13\)

Поскольку \(10\cdot4=40\equiv1\pmod{13}\), имеем

$$m(13)=4.$$

Поэтому

$$13\mid(10q+r)\iff 13\mid(q+4r).$$

Применим правило несколько раз к числу \(3484\):

$$3484 \longrightarrow 348+4\cdot4=364,$$

$$364 \longrightarrow 36+4\cdot4=52,$$

$$52 \longrightarrow 5+4\cdot2=13.$$

Так как \(13\) делится на \(13\), исходное число тоже делится на \(13\). Это показывает, что правило действительно позволяет укорачивать число справа налево.

5) Пример \(p=113\) через расширенный Евклид

В коде есть проверка \(m(113)=34\). Она выводится так:

$$113=11\cdot10+3,\qquad 10=3\cdot3+1.$$

Делаем обратную подстановку:

$$1=10-3\cdot3=10-(113-11\cdot10)\cdot3=34\cdot10-3\cdot113.$$

Значит,

$$10\cdot34\equiv1\pmod{113},$$

то есть

$$m(113)=34.$$

Быстрая проверка на \(791=7\cdot113\):

$$79+34\cdot1=113,$$

и это число уже очевидно делится на \(113\).

6) Почему вся задача сводится к сумме обратных элементов

После вывода формулы больше ничего скрытого не остаётся: для каждого простого \(p\neq2,5\) искомый множитель — это просто \(10^{-1}\pmod p\). Следовательно, задача сводится к вычислению суммы

$$\sum_{\substack{p<L\\ p\ \text{простое}\\ p\neq2,5}} 10^{-1}\!\!\!\pmod p,$$

где всегда берётся наименьший неотрицательный представитель.

Как Работает Код

Генерация простых. primes_up_to() использует линейное решето и строит все простые меньше prime_limit.

Вычисление обратного. inverse_mod_10(p) запускает итеративный расширенный алгоритм Евклида для \(10\) и \(p\), после чего нормализует коэффициент при \(10\) в диапазон \([0,p-1]\).

Накопление суммы. solve() пропускает \(2\) и \(5\), суммирует обратные для остальных простых и возвращает 64-битный результат.

Контрольные точки. Исходник проверяет

$$m(113)=34,\qquad \text{solve}(1000)=39517.$$

Также поддерживаются параметры --prime-limit=... и --skip-checkpoints.

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

Линейное решето до \(L\) требует \(O(L)\) времени и \(O(L)\) памяти. Для каждого простого расширенный Евклид работает за \(O(\log p)\), поэтому дополнительная работа после решета равна

$$O\!\left(\sum_{p<L}\log p\right)=O(\pi(L)\log L).$$

Для предела задачи этого более чем достаточно.

Дополнительные материалы

  1. Условие: https://projecteuler.net/problem=274
  2. Обратный элемент по модулю: https://ru.wikipedia.org/wiki/Обратный_элемент
  3. Расширенный алгоритм Евклида: https://ru.wikipedia.org/wiki/Расширенный_алгоритм_Евклида
  4. Признаки делимости: https://ru.wikipedia.org/wiki/Признак_делимости

ملخص المسألة

لكل عدد أولي \(p\neq2,5\) نعرّف مضاعِف القابلية للقسمة العشري \(m(p)\). هذا العدد يسمح بتحويل اختبار القسمة للعدد

$$n=10q+r$$

إلى اختبار على عدد أقصر هو \(q+m(p)r\). المطلوب هو جمع هذه المضاعفات لكل الأوليات الأصغر من حد كبير. المقصود هنا ليس عرض الناتج النهائي، بل توضيح سبب وجود هذا المضاعف ولماذا تنتهي الشيفرة إلى حساب معكوس \(10\) معيارياً فقط.

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

1) لماذا نُخرج \(2\) و\(5\) من الحساب

كل عدد عشري يمكن كتابته على الصورة

$$n=10q+r,\qquad 0\le r\le 9.$$

إذا كان \(p=2\) أو \(p=5\)، فإن \(10\equiv0\pmod p\)، وبالتالي لا يملك \(10\) معكوساً ضربياً modulo \(p\). لهذا لا يمكن اشتقاق قاعدة “احذف آخر رقم ثم صحّح” بالطريقة نفسها لهذين الأوليين.

أما لأي أولي آخر فلدينا \(\gcd(10,p)=1\)، ولذلك يوجد \(10^{-1}\pmod p\).

2) اشتقاق صيغة المضاعف

نبدأ من شرط القسمة:

$$p\mid n \iff p\mid(10q+r).$$

ليكن \(t\) هو معكوس \(10\) modulo \(p\)، أي

$$10t\equiv1\pmod p.$$

إذا ضربنا العلاقة \(10q+r\equiv0\pmod p\) في \(t\)، نحصل على

$$q+tr\equiv0\pmod p.$$

ومن ثم

$$p\mid n \iff p\mid(q+tr).$$

إذن المضاعف المطلوب هو بالضبط

$$\boxed{m(p)\equiv10^{-1}\pmod p.}$$

وتعيد الشيفرة أصغر ممثل غير سالب لهذا المعكوس.

3) علاقته بقواعد “اطرح آخر رقم” المعروفة

كثير من قواعد القسمة المدرسية تُكتب بصيغة الطرح بدلاً من الجمع. هذا مكافئ تماماً لأن \(m(p)-p\) يمثل نفس الفئة المعيارية التي يمثلها \(m(p)\).

فمثلاً عندما \(p=7\) يكون

$$10^{-1}\equiv5\pmod7,$$

ومن ثم قاعدة صحيحة هي

$$7\mid(10q+r)\iff 7\mid(q+5r).$$

لكن بما أن \(5\equiv-2\pmod7\)، فهذا هو نفسه القانون الشائع

$$7\mid(10q+r)\iff 7\mid(q-2r).$$

مسألة Euler تختار المعكوس الموجب.

4) مثال مفصل: \(p=13\)

بما أن \(10\cdot4=40\equiv1\pmod{13}\)، فإن

$$m(13)=4.$$

وعليه

$$13\mid(10q+r)\iff 13\mid(q+4r).$$

نطبق هذا مراراً على العدد \(3484\):

$$3484 \longrightarrow 348+4\cdot4=364,$$

$$364 \longrightarrow 36+4\cdot4=52,$$

$$52 \longrightarrow 5+4\cdot2=13.$$

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

5) مثال \(p=113\) باستخدام إقليدس الممتد

تتحقق الشيفرة من أن \(m(113)=34\). والسبب هو:

$$113=11\cdot10+3,\qquad 10=3\cdot3+1.$$

وبالرجوع العكسي نحصل على

$$1=10-3\cdot3=10-(113-11\cdot10)\cdot3=34\cdot10-3\cdot113.$$

إذن

$$10\cdot34\equiv1\pmod{113},$$

ومن ثم

$$m(113)=34.$$

وفحص سريع مع \(791=7\cdot113\):

$$79+34\cdot1=113,$$

وهو عدد يقبل القسمة على \(113\) مباشرة.

6) لماذا تختزل المسألة كلها إلى جمع المعكوسات

بعد هذا الاشتقاق لا يبقى شيء خفي: لكل أولي \(p\neq2,5\)، المضاعف المطلوب هو فقط \(10^{-1}\pmod p\). لذلك تصبح المسألة حساب المجموع

$$\sum_{\substack{p<L\\ p\ \text{أولي}\\ p\neq2,5}} 10^{-1}\!\!\!\pmod p,$$

مع أخذ أصغر ممثل غير سالب دائماً.

كيف تعمل الشيفرة

توليد الأوليات. تستعمل primes_up_to() غربالاً خطياً لتوليد جميع الأوليات الأصغر من prime_limit.

حساب المعكوس. تنفذ inverse_mod_10(p) خوارزمية إقليدس الممتدة بشكل تكراري على \(10\) و\(p\)، ثم تطبع معامل \(10\) إلى المجال \([0,p-1]\).

التجميع. تتجاوز solve() العددين \(2\) و\(5\)، وتجمع معكوسات بقية الأوليات في مجموع 64-بت.

نقاط التحقق. يتحقق المصدر من

$$m(113)=34,\qquad \text{solve}(1000)=39517.$$

كما يدعم الوسيطتين --prime-limit=... و--skip-checkpoints.

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

باستخدام الغربال الخطي، يكلف توليد الأوليات حتى \(L\) زمناً \(O(L)\) وذاكرة \(O(L)\). ولكل أولي، تكلف خوارزمية إقليدس الممتدة \(O(\log p)\)، لذا فإن العمل الإضافي بعد الغربال يساوي

$$O\!\left(\sum_{p<L}\log p\right)=O(\pi(L)\log L).$$

وهذا أكثر من كافٍ لحد المسألة.

مراجع إضافية

  1. صفحة المسألة: https://projecteuler.net/problem=274
  2. المعكوس الضربي المعياري: https://ar.wikipedia.org/wiki/معكوس_ضربي
  3. خوارزمية إقليدس الممتدة: https://ar.wikipedia.org/wiki/خوارزمية_إقليدس
  4. قواعد القابلية للقسمة: https://ar.wikipedia.org/wiki/قواعد_القسمة