Problem Summary

We work with the first 51 rows of Pascal's triangle, so the row index runs from \(n=0\) through \(n=50\). From those rows we collect all binomial coefficients \(\binom{n}{k}\), keep only distinct values, and then add the ones that are squarefree.

Define

$$B=\left\{\binom{n}{k}:0\le n\le 50,\ 0\le k\le n\right\}.$$

Let \(Q\subseteq B\) be the subset of squarefree values. The required quantity is

$$A=\sum_{v\in Q} v.$$

The implementations avoid factorial formulas and avoid full prime factorizations. They generate each row multiplicatively, store coefficients in a set so duplicates disappear automatically, and then reject every value that has a square divisor greater than 1.

Mathematical Approach

The problem has only two real mathematical ingredients: how to enumerate binomial coefficients exactly, and how to recognize whether a positive integer is squarefree. Once those are clear, the final sum is just a filtered set sum.

The distinct coefficient set

Pascal's triangle contains many repeated numbers. Some repeats are internal to one row because of the symmetry

$$\binom{n}{k}=\binom{n}{n-k}.$$

Other repeats occur across different rows, for example

$$\binom{5}{2}=10=\binom{10}{1}.$$

Therefore the problem is not asking for a sum over positions \((n,k)\), but over the distinct numerical values that appear. Using the set \(B\) is the mathematically correct way to state that requirement.

Generating one row without factorials

For a fixed row \(n\), the coefficients begin with

$$\binom{n}{0}=1.$$

From there we can move across the row by the multiplicative recurrence

$$\binom{n}{k+1}=\binom{n}{k}\frac{n-k}{k+1},\qquad 0\le k<n.$$

Equivalently, if the update is written before the current coefficient is stored, then

$$\binom{n}{k}=\binom{n}{k-1}\frac{n-k+1}{k},\qquad 1\le k\le n.$$

These are the two equivalent forms used by the implementations. The key invariant is that the current integer always equals the current binomial coefficient, so every division is exact and no floating-point arithmetic is needed. This is much cleaner than computing \(n!\), \(k!\), and \((n-k)!\) separately for every position.

Why the squarefree test works

A positive integer \(v\) is squarefree exactly when no prime square divides it. In other words, \(v\) is rejected if there exists a prime \(p\) such that

$$p^2\mid v.$$

The implementations first test whether

$$4\mid v,$$

which handles the only even prime, namely \(p=2\). After that they scan odd values \(p=3,5,7,\dots\) while \(p^2\le v\), and reject \(v\) as soon as \(p^2\mid v\). Mathematically it would be enough to scan odd primes only, but testing all odd \(p\) is still correct: if \(v\) has any odd square divisor, then it has an odd prime-square divisor, and that divisor will be found during the scan.

Worked example: the first eight rows

The checkpoint built into one implementation uses the first 8 rows, meaning \(n=0,1,\dots,7\). The distinct coefficients appearing there are

$$\{1,2,3,4,5,6,7,10,15,20,21,35\}.$$

Among these, \(4\) is not squarefree because \(4\mid 4\), and \(20\) is not squarefree because \(4\mid 20\). The remaining values

$$\{1,2,3,5,6,7,10,15,21,35\}$$

are all squarefree, so their sum is

$$1+2+3+5+6+7+10+15+21+35=105.$$

This example shows the entire method on a smaller input: generate coefficients, deduplicate them, remove values having a square divisor, and sum what remains.

How the Code Works

Building the distinct coefficient set

The C++, Python, and Java implementations sweep through the rows one by one. For each row they maintain the current coefficient, insert it into a set, and update it by the multiplicative recurrence to obtain the next coefficient in the row. Because the container stores unique integers, repeated values from row symmetry or from different rows are automatically collapsed into one entry.

Filtering squarefree values and summing

After the set has been built, the implementation iterates through its stored coefficients. A defensive zero check appears in the squarefree routine, although every actual binomial coefficient here is positive. Then the algorithm rejects multiples of \(4\), checks odd squares up to \(\sqrt{v}\), and adds \(v\) to the running total only if no square divisor is found. One implementation also verifies the 8-row checkpoint \(105\) before solving the full 51-row case.

Complexity Analysis

If the first \(R\) rows are processed, coefficient generation touches

$$\sum_{n=0}^{R-1}(n+1)=\frac{R(R+1)}{2}$$

positions, so the row sweep is \(O(R^2)\). Let \(U\) be the number of distinct coefficients collected and let \(M\) be the largest such coefficient. The squarefree filtering stage costs \(O(U\sqrt{M})\) trial divisions in the worst case, because each test scans odd candidates up to \(\sqrt{v}\).

Memory usage is \(O(U)\) for the set of distinct coefficients. For the actual problem, \(R=51\), so only 1326 coefficient positions are visited, and the largest values still fit comfortably in 64-bit integer arithmetic. That is why the direct set-and-test approach is entirely sufficient here.

Footnotes and References

  1. Problem page: https://projecteuler.net/problem=203
  2. Pascal's triangle: Wikipedia - Pascal's triangle
  3. Binomial coefficient: Wikipedia - Binomial coefficient
  4. Square-free integer: Wikipedia - Square-free integer

Problemzusammenfassung

Betrachtet werden die ersten 51 Zeilen des Pascalschen Dreiecks, also die Zeilenindizes \(n=0\) bis \(n=50\). Aus diesen Zeilen werden alle Binomialkoeffizienten \(\binom{n}{k}\) gesammelt, gleiche Werte zusammengefasst und anschließend nur die quadratfreien Werte addiert.

Definiere

$$B=\left\{\binom{n}{k}:0\le n\le 50,\ 0\le k\le n\right\}.$$

Sei \(Q\subseteq B\) die Teilmenge der quadratfreien Werte. Gesucht ist dann

$$A=\sum_{v\in Q} v.$$

Die Implementierungen verwenden dafür weder Fakultätsformeln noch eine vollständige Primfaktorzerlegung jedes Wertes. Stattdessen erzeugen sie jede Zeile multiplikativ, speichern alle Koeffizienten in einer Menge und verwerfen danach genau die Zahlen, die durch ein Quadrat größer als 1 teilbar sind.

Mathematischer Ansatz

Der Kern des Problems besteht aus zwei präzisen Fragen: Wie erzeugt man die Binomialkoeffizienten exakt und effizient, und wie erkennt man sicher, ob ein positiver Integer quadratfrei ist? Wenn diese beiden Punkte klar sind, bleibt nur noch eine gefilterte Summe über eine Menge übrig.

Die Menge der verschiedenen Koeffizienten

Im Pascalschen Dreieck treten viele Werte mehrfach auf. Innerhalb einer einzelnen Zeile gilt wegen der Symmetrie

$$\binom{n}{k}=\binom{n}{n-k}.$$

Außerdem tauchen gleiche Zahlen in verschiedenen Zeilen wieder auf, etwa

$$\binom{5}{2}=10=\binom{10}{1}.$$

Darum wird nicht über Positionen \((n,k)\) summiert, sondern über die verschiedenen Zahlenwerte selbst. Genau dafür steht die Menge \(B\): Jeder numerische Wert soll höchstens einmal zum Endergebnis beitragen.

Eine Zeile ohne Fakultäten erzeugen

Für eine feste Zeile \(n\) beginnt man mit

$$\binom{n}{0}=1.$$

Die restlichen Einträge folgen aus der Rekurrenz

$$\binom{n}{k+1}=\binom{n}{k}\frac{n-k}{k+1},\qquad 0\le k<n.$$

Äquivalent dazu kann man schreiben

$$\binom{n}{k}=\binom{n}{k-1}\frac{n-k+1}{k},\qquad 1\le k\le n.$$

Diese beiden Schreibweisen entsprechen genau der Position des Updates in den Implementierungen. Die zentrale Invariante lautet: Im inneren Schleifendurchlauf ist der aktuelle Ganzzahlwert stets genau der aktuelle Binomialkoeffizient. Deshalb sind die Divisionen in jedem Schritt exakt, und es wird keinerlei Fließkommaarithmetik benötigt.

Warum der Quadratfreiheits-Test genügt

Eine positive ganze Zahl \(v\) ist genau dann quadratfrei, wenn kein Primquadrat \(p^2\) sie teilt. Also wird \(v\) verworfen, sobald es ein \(p\) mit

$$p^2\mid v$$

gibt. Die Implementierungen testen zuerst

$$4\mid v,$$

was den einzigen geraden Primfall \(p=2\) vollständig abdeckt. Danach werden ungerade Werte \(p=3,5,7,\dots\) mit \(p^2\le v\) ausprobiert, und \(v\) wird verworfen, sobald \(p^2\mid v\) gilt. Mathematisch würde es genügen, nur ungerade Primzahlen zu testen; alle ungeraden \(p\) zu prüfen ist jedoch ebenfalls korrekt, nur etwas redundanter.

Durchgerechnetes Beispiel: die ersten acht Zeilen

Ein eingebauter Kontrollfall benutzt die ersten 8 Zeilen, also \(n=0,1,\dots,7\). Die dort auftretenden verschiedenen Koeffizienten sind

$$\{1,2,3,4,5,6,7,10,15,20,21,35\}.$$

Davon sind \(4\) und \(20\) nicht quadratfrei, weil beide durch \(4\) teilbar sind. Übrig bleiben

$$\{1,2,3,5,6,7,10,15,21,35\}.$$

Ihre Summe ist

$$1+2+3+5+6+7+10+15+21+35=105.$$

Dieses Beispiel enthält bereits die komplette Logik der Aufgabe in kleiner Form: Koeffizienten erzeugen, Werte deduplizieren, Vielfache von Quadraten entfernen und den Rest aufsummieren.

Wie der Code arbeitet

Aufbau der Menge verschiedener Koeffizienten

Die C++-, Python- und Java-Implementierungen durchlaufen die Zeilen nacheinander. Für jede Zeile halten sie den aktuellen Koeffizienten, fügen ihn in eine Menge ein und aktualisieren ihn mit der multiplikativen Rekurrenz zum nächsten Zeileneintrag. Weil die Datenstruktur nur verschiedene Ganzzahlen speichert, werden Wiederholungen aus Symmetrie oder aus anderen Zeilen automatisch auf einen Eintrag reduziert.

Quadratfreie Werte filtern und aufsummieren

Nach dem Aufbau der Menge wird über alle gespeicherten Koeffizienten iteriert. Die Quadratfreiheitsroutine enthält defensiv auch einen Test auf \(v=0\), obwohl hier tatsächlich alle Binomialkoeffizienten positiv sind. Danach werden Vielfache von \(4\) ausgeschlossen, dann ungerade Quadrate bis \(\sqrt{v}\) geprüft, und nur Werte ohne Quadratfaktor werden zur Summe addiert. Eine Implementierung verifiziert zusätzlich vor dem Hauptlauf den Kontrollwert \(105\) für die ersten 8 Zeilen.

Komplexitätsanalyse

Werden die ersten \(R\) Zeilen verarbeitet, so werden insgesamt

$$\sum_{n=0}^{R-1}(n+1)=\frac{R(R+1)}{2}$$

Koeffizientenpositionen besucht. Der Zeilendurchlauf kostet also \(O(R^2)\). Sei \(U\) die Anzahl verschiedener Koeffizienten und \(M\) der größte davon. Dann benötigt die Filterphase im Worst Case \(O(U\sqrt{M})\) Testdivisionen, weil jeder Wert mit ungeraden Kandidaten bis \(\sqrt{v}\) geprüft wird.

Der Speicherverbrauch ist \(O(U)\) für die Menge der verschiedenen Koeffizienten. Im konkreten Problem mit \(R=51\) sind das nur 1326 besuchte Positionen, und selbst die größten vorkommenden Koeffizienten liegen noch bequem im 64-Bit-Bereich. Deshalb ist dieser direkte Ansatz hier völlig ausreichend.

Fußnoten und Referenzen

  1. Problemseite: https://projecteuler.net/problem=203
  2. Pascalsches Dreieck: Wikipedia - Pascal's triangle
  3. Binomialkoeffizient: Wikipedia - Binomial coefficient
  4. Quadratfreie Zahl: Wikipedia - Square-free integer

Problem Özeti

Pascal üçgeninin ilk 51 satırı ele alınıyor; yani satır indisi \(n=0\) ile \(n=50\) arasında değişiyor. Bu satırlardaki tüm binom katsayıları \(\binom{n}{k}\) toplanıyor, tekrar eden sayısal değerler tekilleştiriliyor ve ardından sadece karefree olanlar toplanıyor.

Şu kümeyi tanımlayalım:

$$B=\left\{\binom{n}{k}:0\le n\le 50,\ 0\le k\le n\right\}.$$

\(Q\subseteq B\), karefree değerlerin altkümesi olsun. İstenen büyüklük

$$A=\sum_{v\in Q} v$$

olur. Uygulamalar bunu yapmak için faktöriyel formüllerini veya her sayı için tam asal çarpanlara ayırmayı kullanmaz; bunun yerine katsayıları satır satır çarpımsal olarak üretir, bir kümeye koyarak tekilleştirir ve kare böleni olanları eler.

Matematiksel Yaklaşım

Bu problemde gerçekten gerekli olan iki matematiksel fikir vardır: binom katsayılarını tam sayı olarak verimli biçimde üretmek ve bir sayının karefree olup olmadığını doğru biçimde test etmek. Geriye kalan şey, bu iki aracın birleştiği filtrelenmiş bir küme toplamıdır.

Farklı katsayılar kümesi

Pascal üçgeninde aynı değer birçok kez ortaya çıkabilir. Aynı satır içinde

$$\binom{n}{k}=\binom{n}{n-k}$$

simetrisi vardır. Ayrıca farklı satırlarda da tekrarlar bulunur; örneğin

$$\binom{5}{2}=10=\binom{10}{1}.$$

Dolayısıyla toplanması gereken şey, konumların toplamı değil, görünen farklı sayısal değerlerin toplamıdır. \(B\) kümesi tam olarak bu nesneyi temsil eder: her katsayı değeri en fazla bir kez katkı yapar.

Bir satırı faktöriyel kullanmadan üretmek

Sabit bir \(n\) satırı için başlangıç değeri

$$\binom{n}{0}=1$$

olur. Sonraki katsayılar şu çarpımsal bağıntıyla elde edilir:

$$\binom{n}{k+1}=\binom{n}{k}\frac{n-k}{k+1},\qquad 0\le k<n.$$

Aynı fikir, güncellemenin döngüdeki yerine bağlı olarak

$$\binom{n}{k}=\binom{n}{k-1}\frac{n-k+1}{k},\qquad 1\le k\le n$$

şeklinde de yazılabilir. Uygulamalarda görülen tam olarak bu iki eşdeğer formdur. Temel değişmez şudur: iç döngüdeki mevcut tam sayı, o anda işlenmekte olan binom katsayısına eşittir. Bu yüzden her bölme tam çıkar ve kayan nokta aritmetiğine gerek kalmaz.

Karefree testinin doğruluğu

Pozitif bir \(v\) tam sayısı, ancak ve ancak hiçbir asalın karesi onu bölmüyorsa karefree'dir. Yani reddedilme ölçütü

$$p^2\mid v$$

olacak bir asal \(p\) bulunmasıdır. Uygulamalar önce

$$4\mid v$$

kontrolünü yapar; bu, tek çift asal olan \(p=2\) durumunu tamamen kapsar. Sonra \(p=3,5,7,\dots\) olacak şekilde tek sayılar denenir ve \(p^2\le v\) olduğu sürece herhangi bir \(p^2\mid v\) durumu bulunursa sayı elenir. Matematiksel olarak yalnızca tek asalları denemek yeterli olurdu; fakat tüm tek \(p\) değerlerini denemek de doğrudur, sadece biraz daha fazladan kontrol yapar.

Çalışılmış örnek: ilk sekiz satır

Uygulamalardan birindeki kontrol örneği ilk 8 satırı, yani \(n=0,1,\dots,7\) durumunu kullanır. Bu satırlarda görülen farklı katsayılar

$$\{1,2,3,4,5,6,7,10,15,20,21,35\}$$

kümesidir. Bunlardan \(4\) ve \(20\), \(4\)'e bölündükleri için karefree değildir. Geriye

$$\{1,2,3,5,6,7,10,15,21,35\}$$

kalır ve toplamları

$$1+2+3+5+6+7+10+15+21+35=105$$

eder. Küçük örnekte yapılan şey, büyük örnekte yapılan şeyin aynısıdır: üret, tekilleştir, kare böleni olanları çıkar, kalanı topla.

Kod Nasıl Çalışır

Farklı katsayılar kümesini kurma

C++, Python ve Java uygulamaları satırları sırayla dolaşır. Her satır için mevcut katsayıyı tutar, onu kümeye ekler ve çarpımsal bağıntıyla bir sonraki katsayıya geçer. Kullanılan veri yapısı yalnızca benzersiz tam sayıları tuttuğu için hem satır içi simetriden gelen tekrarlar hem de farklı satırlardaki tekrarlar otomatik olarak tek kayda iner.

Karefree değerleri süzme ve toplamı biriktirme

Küme oluşturulduktan sonra saklanan tüm katsayılar üzerinden geçilir. Karefree yordamında savunmacı olarak \(v=0\) kontrolü de vardır; gerçekte burada tüm binom katsayıları pozitiftir. Sonrasında \(4\)'ün katları elenir, \(\sqrt{v}\)'ye kadar olan tek kareler denenir ve kare böleni bulunmayan her değer toplama eklenir. Uygulamalardan biri ayrıca tam örneğe geçmeden önce ilk 8 satır için \(105\) sonucunu doğrular.

Karmaşıklık Analizi

İlk \(R\) satır işlendiğinde toplam

$$\sum_{n=0}^{R-1}(n+1)=\frac{R(R+1)}{2}$$

adet katsayı konumu ziyaret edilir; dolayısıyla satır üretimi \(O(R^2)\) maliyetlidir. \(U\), tekilleştirilmiş katsayı sayısı; \(M\) ise bunların en büyüğü olsun. Karefree filtresi en kötü durumda \(O(U\sqrt{M})\) bölünebilme testi yapar; çünkü her \(v\) için \(\sqrt{v}\)'ye kadar tek adaylar denenir.

Bellek kullanımı, farklı katsayılar kümesi için \(O(U)\)'dur. Gerçek problemde \(R=51\) olduğu için yalnızca 1326 katsayı konumu üretilir ve en büyük değerler bile 64 bit tam sayı aralığında rahatça tutulur. Bu yüzden doğrudan küme kurup test etme yaklaşımı burada fazlasıyla yeterlidir.

Dipnotlar ve Kaynaklar

  1. Problem sayfası: https://projecteuler.net/problem=203
  2. Pascal üçgeni: Wikipedia - Pascal's triangle
  3. Binom katsayısı: Wikipedia - Binomial coefficient
  4. Karefree tam sayı: Wikipedia - Square-free integer

Resumen del Problema

Se toman las primeras 51 filas del triángulo de Pascal, es decir, las filas con índice \(n=0\) hasta \(n=50\). De esas filas se recogen todos los coeficientes binomiales \(\binom{n}{k}\), se eliminan los valores repetidos y luego se suman únicamente los que son libres de cuadrados.

Definimos

$$B=\left\{\binom{n}{k}:0\le n\le 50,\ 0\le k\le n\right\}.$$

Sea \(Q\subseteq B\) el subconjunto formado por los valores libres de cuadrados. La cantidad pedida es

$$A=\sum_{v\in Q} v.$$

Las implementaciones no recurren a factoriales ni a una factorización prima completa de cada valor. En su lugar generan cada fila de forma multiplicativa, guardan los coeficientes en un conjunto para deduplicarlos automáticamente y descartan cualquier valor que tenga un divisor cuadrado mayor que 1.

Enfoque Matemático

El problema se apoya en dos ideas concretas: cómo recorrer exactamente los coeficientes binomiales de Pascal y cómo decidir si un entero positivo es libre de cuadrados. Una vez fijadas esas dos piezas, la respuesta es simplemente una suma sobre un conjunto filtrado.

El conjunto de coeficientes distintos

En el triángulo de Pascal aparecen muchas repeticiones. Dentro de una misma fila existe la simetría

$$\binom{n}{k}=\binom{n}{n-k}.$$

Además, el mismo número puede reaparecer en filas distintas; por ejemplo,

$$\binom{5}{2}=10=\binom{10}{1}.$$

Por eso no hay que sumar posiciones \((n,k)\), sino valores numéricos distintos. El conjunto \(B\) expresa exactamente ese objeto: cada coeficiente contribuye como número, no como aparición individual.

Generar una fila sin usar factoriales

Para una fila fija \(n\), el primer valor es

$$\binom{n}{0}=1.$$

Los siguientes coeficientes se obtienen mediante la recurrencia multiplicativa

$$\binom{n}{k+1}=\binom{n}{k}\frac{n-k}{k+1},\qquad 0\le k<n.$$

De forma equivalente, si la actualización se hace antes de registrar el valor actual, se puede escribir

$$\binom{n}{k}=\binom{n}{k-1}\frac{n-k+1}{k},\qquad 1\le k\le n.$$

Estas dos variantes son exactamente las que usan las implementaciones según la posición del paso de actualización. La invariante esencial es que el entero actual siempre coincide con el coeficiente binomial que se está procesando. Por eso cada división es exacta y no hace falta aritmética en coma flotante.

Por qué funciona la prueba de squarefree

Un entero positivo \(v\) es libre de cuadrados si y solo si ningún cuadrado primo lo divide. Es decir, se debe rechazar \(v\) cuando exista algún primo \(p\) tal que

$$p^2\mid v.$$

Las implementaciones comienzan comprobando si

$$4\mid v,$$

lo cual cubre completamente el caso del único primo par, \(p=2\). Después prueban valores impares \(p=3,5,7,\dots\) mientras \(p^2\le v\), y rechazan el número tan pronto como encuentran \(p^2\mid v\). Desde el punto de vista matemático bastaría con revisar solo primos impares, pero probar todos los \(p\) impares sigue siendo correcto, aunque haga algunas comprobaciones redundantes.

Ejemplo trabajado: las primeras ocho filas

Uno de los controles usados por la implementación toma las primeras 8 filas, es decir, \(n=0,1,\dots,7\). Los coeficientes distintos que aparecen son

$$\{1,2,3,4,5,6,7,10,15,20,21,35\}.$$

De ellos, \(4\) y \(20\) no son libres de cuadrados porque ambos son divisibles por \(4\). Por tanto sobreviven

$$\{1,2,3,5,6,7,10,15,21,35\}$$

y su suma es

$$1+2+3+5+6+7+10+15+21+35=105.$$

Ese ejemplo pequeño ya contiene todo el esquema de la solución completa: generar, deduplicar, eliminar los valores con divisor cuadrado y sumar el resto.

Cómo Funciona el Código

Construcción del conjunto de coeficientes distintos

Las implementaciones en C++, Python y Java recorren las filas una a una. En cada fila mantienen el coeficiente actual, lo insertan en un conjunto y luego lo actualizan con la recurrencia multiplicativa para obtener el siguiente elemento de la fila. Como la estructura solo conserva enteros únicos, las repeticiones por simetría o entre filas distintas desaparecen automáticamente.

Filtrado de valores libres de cuadrados y suma final

Una vez construido el conjunto, la implementación recorre sus coeficientes almacenados. La rutina de squarefree incluye de forma defensiva una comprobación de \(v=0\), aunque aquí todos los coeficientes binomiales reales son positivos. Luego descarta múltiplos de \(4\), prueba cuadrados impares hasta \(\sqrt{v}\) y suma únicamente los valores que no contienen ningún divisor cuadrado. Una de las implementaciones también verifica antes el caso de control de 8 filas con resultado \(105\).

Análisis de Complejidad

Si se procesan las primeras \(R\) filas, la generación de coeficientes visita

$$\sum_{n=0}^{R-1}(n+1)=\frac{R(R+1)}{2}$$

posiciones, por lo que este barrido cuesta \(O(R^2)\). Sea \(U\) el número de coeficientes distintos recogidos y sea \(M\) el mayor de ellos. La fase de filtrado squarefree cuesta \(O(U\sqrt{M})\) divisiones de prueba en el peor caso, porque cada test recorre candidatos impares hasta \(\sqrt{v}\).

La memoria utilizada es \(O(U)\) para almacenar el conjunto de coeficientes distintos. En el caso real, \(R=51\), así que solo se visitan 1326 posiciones del triángulo, y los valores máximos siguen estando muy por debajo del límite de enteros de 64 bits. Por eso un enfoque directo con conjunto más prueba de divisibilidad resulta suficiente.

Notas y Referencias

  1. Página del problema: https://projecteuler.net/problem=203
  2. Triángulo de Pascal: Wikipedia - Pascal's triangle
  3. Coeficiente binomial: Wikipedia - Binomial coefficient
  4. Entero libre de cuadrados: Wikipedia - Square-free integer

问题概述

本题处理的是 Pascal 三角形的前 51 行,也就是行指标从 \(n=0\) 到 \(n=50\)。我们把这些行里出现的全部二项式系数 \(\binom{n}{k}\) 收集起来,先按数值去重,再把其中所有无平方因子整数相加。

$$B=\left\{\binom{n}{k}:0\le n\le 50,\ 0\le k\le n\right\}.$$

再令 \(Q\subseteq B\) 表示其中无平方因子的那些值,那么题目要求计算

$$A=\sum_{v\in Q} v.$$

实现并没有去直接套用阶乘公式,也没有对每个数做完整质因数分解。它们采用的是更贴近题意的做法:逐行生成二项式系数,用集合保留不同的数值,然后检查每个值是否含有大于 1 的平方因子。

数学方法

这道题真正用到的数学内容并不多,但每一步都很具体。第一步是准确地枚举 Pascal 三角形中的二项式系数;第二步是判断一个正整数是否 squarefree。只要这两步建立起来,最后就是对一个经过筛选的集合求和。

先明确“去重以后再求和”

Pascal 三角形里的数值会重复出现,而且重复不止一种来源。首先,在同一行内部有对称性

$$\binom{n}{k}=\binom{n}{n-k}.$$

其次,同一个数也可能出现在不同的行里,例如

$$\binom{5}{2}=10=\binom{10}{1}.$$

因此题目要求求和的对象不是所有位置 \((n,k)\),而是所有出现过的不同数值本身。把目标对象写成集合 \(B\),就把“相同数值只算一次”这件事表达得非常明确。

用乘法递推逐行生成二项式系数

对于固定的第 \(n\) 行,起点一定是

$$\binom{n}{0}=1.$$

之后可以用下面的递推式向右推进:

$$\binom{n}{k+1}=\binom{n}{k}\frac{n-k}{k+1},\qquad 0\le k<n.$$

如果把更新写在“存入当前值”之前,也可以改写成

$$\binom{n}{k}=\binom{n}{k-1}\frac{n-k+1}{k},\qquad 1\le k\le n.$$

这两个公式完全等价,只是与不同实现中更新语句出现的位置对应。这里最重要的不变量是:内层循环手上的当前整数,始终就是当前要处理的二项式系数。所以每一步里的除法都是整除,不会出现误差,也不需要任何浮点计算。与对每个位置都重新计算一次阶乘相比,这个递推更直接,也更符合代码的实际结构。

为何这样检查 squarefree 是正确的

正整数 \(v\) 是无平方因子的,当且仅当没有任何素数平方 \(p^2\) 整除它。也就是说,一旦存在

$$p^2\mid v,$$

它就应该被排除。实现先单独检查

$$4\mid v,$$

这一步已经完整处理了唯一的偶素数 \(p=2\)。然后它从 \(p=3,5,7,\dots\) 开始,依次尝试奇数,只要 \(p^2\le v\) 就继续;一旦发现 \(p^2\mid v\),就立刻判定这个数不是 squarefree。从纯数学角度说,只检查奇素数就够了;但把所有奇数都试一遍同样是正确的,只是会做一些多余但无害的检查。

具体例子:前八行为什么得到 105

代码中的一个校验案例使用前 8 行,也就是 \(n=0,1,\dots,7\)。这些行中出现的不同二项式系数恰好是

$$\{1,2,3,4,5,6,7,10,15,20,21,35\}.$$

其中 \(4\) 不是 squarefree,因为 \(4\mid 4\);\(20\) 也不是 squarefree,因为 \(4\mid 20\)。于是留下来的数是

$$\{1,2,3,5,6,7,10,15,21,35\}.$$

把它们相加得到

$$1+2+3+5+6+7+10+15+21+35=105.$$

这个例子几乎就是整道题的缩小版:先生成所有系数,再去重,再删掉含平方因子的项,最后求和。大规模输入并没有新的数学障碍,只是把同样的过程应用到前 51 行。

代码如何工作

先构造“不同系数”的集合

C++、Python 和 Java 三个实现都按行扫描 Pascal 三角形。处理每一行时,它们维护当前系数,把它放进集合,然后根据乘法递推得到下一个系数。由于集合只保留不同的整数,所以无论重复来自同一行的左右对称,还是来自不同行之间的数值重现,最终都只保留一份。

再筛掉含平方因子的值并累计答案

建立好集合之后,实现会遍历其中的每个系数。squarefree 判定函数里先做一个防御性的 \(v=0\) 检查,虽然这里真正出现的二项式系数全都大于 0。随后它排除 \(4\) 的倍数,再检查不超过 \(\sqrt{v}\) 的奇平方;如果没有找到平方因子,这个值就加入总和。还有一个实现会先验证前 8 行的结果确实是 \(105\),再继续求正式答案。

复杂度分析

如果把前 \(R\) 行都处理一遍,那么被访问的系数位置总数是

$$\sum_{n=0}^{R-1}(n+1)=\frac{R(R+1)}{2},$$

因此逐行生成阶段的时间复杂度是 \(O(R^2)\)。设去重后的不同系数个数为 \(U\),其中最大值为 \(M\)。那么 squarefree 过滤阶段在最坏情况下需要 \(O(U\sqrt{M})\) 次试除,因为每个待测值都要检查到 \(\sqrt{v}\) 为止的奇数候选。

空间复杂度是 \(O(U)\),主要用来存储这些不同的二项式系数。对本题的实际参数 \(R=51\) 来说,一共只会访问 1326 个三角形位置,而且最大系数仍然远在 64 位整数范围之内,所以这种直接的“生成 + 去重 + 试除”方案完全足够。

脚注与参考资料

  1. 题目页面:https://projecteuler.net/problem=203
  2. Pascal 三角形:Wikipedia - Pascal's triangle
  3. 二项式系数:Wikipedia - Binomial coefficient
  4. 无平方因子整数:Wikipedia - Square-free integer

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

Рассматриваются первые 51 строка треугольника Паскаля, то есть строки с индексами от \(n=0\) до \(n=50\). Из них берутся все биномиальные коэффициенты \(\binom{n}{k}\), одинаковые числовые значения оставляются только в одном экземпляре, а затем суммируются лишь квадратсвободные числа.

Обозначим

$$B=\left\{\binom{n}{k}:0\le n\le 50,\ 0\le k\le n\right\}.$$

Пусть \(Q\subseteq B\) состоит из квадратсвободных значений. Тогда требуется вычислить

$$A=\sum_{v\in Q} v.$$

Реализации не строят коэффициенты через факториалы и не выполняют полное разложение каждого числа на простые множители. Вместо этого они порождают строки по мультипликативной рекуррентной формуле, складывают коэффициенты в множество и затем отбрасывают все значения, имеющие квадратный делитель больше 1.

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

У задачи есть две основные математические опоры. Первая состоит в том, чтобы точно и без потерь перечислить биномиальные коэффициенты. Вторая состоит в корректной проверке условия squarefree. После этого ответ становится просто суммой по отфильтрованному множеству различных значений.

Множество различных биномиальных коэффициентов

В треугольнике Паскаля одно и то же число часто встречается несколько раз. Внутри одной строки действует симметрия

$$\binom{n}{k}=\binom{n}{n-k}.$$

Кроме того, совпадения бывают и между разными строками; например,

$$\binom{5}{2}=10=\binom{10}{1}.$$

Поэтому задача суммирует не позиции \((n,k)\), а сами различные числовые значения. Именно это и выражает множество \(B\): каждый коэффициент учитывается как число, а не как отдельное место в треугольнике.

Порождение строки без факториалов

Для фиксированной строки \(n\) первым коэффициентом является

$$\binom{n}{0}=1.$$

Далее можно переходить к следующему элементу по формуле

$$\binom{n}{k+1}=\binom{n}{k}\frac{n-k}{k+1},\qquad 0\le k<n.$$

Эквивалентно, если обновление делается перед сохранением текущего значения, удобно писать

$$\binom{n}{k}=\binom{n}{k-1}\frac{n-k+1}{k},\qquad 1\le k\le n.$$

Именно эти две формы и встречаются в реализациях. Главная инварианта очень проста: текущее целое число в внутреннем цикле всегда равно текущему биномиальному коэффициенту. Поэтому каждая операция деления точна, и никакая вещественная арифметика не нужна.

Почему проверка squarefree корректна

Положительное целое число \(v\) является квадратсвободным тогда и только тогда, когда никакой квадрат простого числа его не делит. Иначе говоря, число нужно отвергнуть, если найдется простой \(p\) такой, что

$$p^2\mid v.$$

Сначала реализации проверяют условие

$$4\mid v,$$

что полностью покрывает случай единственного четного простого \(p=2\). Затем перебираются нечетные значения \(p=3,5,7,\dots\) до тех пор, пока \(p^2\le v\), и число отбрасывается сразу, как только выполнится \(p^2\mid v\). С математической точки зрения достаточно было бы проверять только нечетные простые, но перебор всех нечетных \(p\) тоже остается правильным, просто содержит лишние проверки.

Разобранный пример: первые восемь строк

Во встроенной проверке используется случай первых 8 строк, то есть \(n=0,1,\dots,7\). Множество различных коэффициентов там равно

$$\{1,2,3,4,5,6,7,10,15,20,21,35\}.$$

Числа \(4\) и \(20\) не являются квадратсвободными, потому что делятся на \(4\). Остаются значения

$$\{1,2,3,5,6,7,10,15,21,35\},$$

и их сумма равна

$$1+2+3+5+6+7+10+15+21+35=105.$$

Этот пример уже полностью иллюстрирует алгоритм: породить коэффициенты, убрать повторы, отбросить числа с квадратным делителем и сложить все оставшиеся.

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

Построение множества различных коэффициентов

Реализации на C++, Python и Java проходят строки по очереди. В каждой строке они держат текущий коэффициент, помещают его в множество, а затем обновляют по мультипликативной формуле до следующего коэффициента. Поскольку структура хранения допускает только уникальные целые значения, симметричные повторы внутри строки и совпадения между разными строками автоматически схлопываются.

Фильтрация squarefree и накопление суммы

После построения множества реализация обходит все сохраненные коэффициенты. В функции проверки есть защитная проверка \(v=0\), хотя фактически все биномиальные коэффициенты здесь положительны. Затем отбрасываются кратные \(4\), проверяются нечетные квадраты до \(\sqrt{v}\), и только значения без квадратного делителя добавляются к общей сумме. Одна из реализаций дополнительно подтверждает контрольный результат \(105\) для первых 8 строк перед полным запуском.

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

Если обрабатываются первые \(R\) строк, то количество посещаемых позиций равно

$$\sum_{n=0}^{R-1}(n+1)=\frac{R(R+1)}{2},$$

поэтому генерация коэффициентов имеет сложность \(O(R^2)\). Пусть \(U\) обозначает число различных коэффициентов, а \(M\) - максимальный из них. Тогда стадия проверки squarefree стоит \(O(U\sqrt{M})\) пробных делений в худшем случае, потому что для каждого значения перебираются нечетные кандидаты до \(\sqrt{v}\).

По памяти требуется \(O(U)\) для хранения множества различных коэффициентов. В реальной задаче \(R=51\), так что всего просматривается 1326 позиций треугольника, а наибольшие значения по-прежнему легко помещаются в 64-битные целые. Именно поэтому здесь достаточно прямого подхода «сгенерировать, дедуплицировать, проверить».

Сноски и ссылки

  1. Страница задачи: https://projecteuler.net/problem=203
  2. Треугольник Паскаля: Wikipedia - Pascal's triangle
  3. Биномиальный коэффициент: Wikipedia - Binomial coefficient
  4. Квадратсвободное число: Wikipedia - Square-free integer

ملخص المسألة

ننظر إلى أول 51 صفًا من مثلث باسكال، أي الصفوف ذات الفهرس من \(n=0\) حتى \(n=50\). نأخذ جميع معاملات ثنائية الحد \(\binom{n}{k}\) التي تظهر في هذه الصفوف، ثم نزيل التكرارات بحسب القيمة العددية، وبعد ذلك نجمع فقط القيم الخالية من العوامل المربعة.

لنعرّف

$$B=\left\{\binom{n}{k}:0\le n\le 50,\ 0\le k\le n\right\}.$$

ولتكن \(Q\subseteq B\) هي مجموعة القيم الخالية من المربعات. إذن الكمية المطلوبة هي

$$A=\sum_{v\in Q} v.$$

التنفيذات لا تعتمد على صيغ المضروب المباشرة، ولا تقوم بتحليل أولي كامل لكل قيمة. الفكرة الفعلية هي توليد كل صف بطريقة ضربية، وتخزين القيم في مجموعة لإزالة التكرار تلقائيًا، ثم استبعاد كل عدد يقبل القسمة على مربع أكبر من 1.

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

جوهر المسألة يعتمد على فكرتين واضحتين: كيف نولد معاملات ثنائية الحد بدقة ومن غير كلفة زائدة، وكيف نتحقق من أن عددًا موجبًا ما هو squarefree بالفعل. بعد ذلك تصبح المهمة مجرد جمع عناصر مجموعة بعد ترشيحها.

مجموعة المعاملات المختلفة

القيم في مثلث باسكال تتكرر كثيرًا. داخل الصف الواحد توجد التناظرية

$$\binom{n}{k}=\binom{n}{n-k}.$$

كما أن القيمة نفسها قد تظهر في صفوف مختلفة، مثل

$$\binom{5}{2}=10=\binom{10}{1}.$$

لذلك المطلوب ليس جمع جميع المواضع \((n,k)\)، بل جمع القيم العددية المختلفة التي تظهر. وتمثيل ذلك بالمجموعة \(B\) هو الصياغة الرياضية الصحيحة لفكرة "احسب كل قيمة مرة واحدة فقط".

توليد الصف من غير استخدام المضاريب

لصف ثابت \(n\) نبدأ بالقيمة

$$\binom{n}{0}=1.$$

ثم نتحرك عبر الصف باستعمال العلاقة الضربية

$$\binom{n}{k+1}=\binom{n}{k}\frac{n-k}{k+1},\qquad 0\le k<n.$$

وبصورة مكافئة، إذا كان التحديث يحدث قبل تخزين القيمة الحالية، يمكن كتابتها على الصورة

$$\binom{n}{k}=\binom{n}{k-1}\frac{n-k+1}{k},\qquad 1\le k\le n.$$

هاتان الصيغتان هما بالضبط ما تستعمله التنفيذات وفقًا لموضع خطوة التحديث داخل الحلقة. والثابت المهم هنا هو أن العدد الصحيح الحالي يساوي دائمًا المعامل الثنائي الجاري معالجته. لهذا تكون القسمة دقيقة في كل خطوة، ولا توجد حاجة إلى أعداد عشرية أو تقريب.

لماذا ينجح اختبار squarefree

العدد الصحيح الموجب \(v\) يكون خاليًا من المربعات إذا وفقط إذا لم يوجد عدد أولي \(p\) يحقق

$$p^2\mid v.$$

ولهذا تبدأ التنفيذات باختبار

$$4\mid v,$$

وهو ما يغطي حالة العدد الأولي الزوجي الوحيد \(p=2\). بعد ذلك تُجرَّب القيم الفردية \(p=3,5,7,\dots\) ما دام \(p^2\le v\)، ويُرفض العدد مباشرة عند العثور على حالة \(p^2\mid v\). من الناحية الرياضية يكفي أن نختبر الأعداد الأولية الفردية فقط، لكن اختبار جميع القيم الفردية يبقى صحيحًا أيضًا، وإن كان يتضمن بعض الفحوص الزائدة.

مثال محلول: أول ثمانية صفوف

أحد اختبارات التحقق المضمنة يستعمل أول 8 صفوف، أي \(n=0,1,\dots,7\). القيم المختلفة التي تظهر هناك هي

$$\{1,2,3,4,5,6,7,10,15,20,21,35\}.$$

القيمتان \(4\) و\(20\) ليستا خاليتين من المربعات لأن كلتيهما تقبل القسمة على \(4\). إذن تبقى القيم

$$\{1,2,3,5,6,7,10,15,21,35\}$$

ويكون مجموعها

$$1+2+3+5+6+7+10+15+21+35=105.$$

هذا المثال الصغير يبين الخطة كلها كما هي: توليد المعاملات، إزالة التكرار، حذف الأعداد ذات القاسم المربع، ثم جمع الباقي.

كيف يعمل الكود

بناء مجموعة المعاملات المختلفة

تنفيذات C++ وPython وJava تمر على الصفوف واحدًا بعد الآخر. في كل صف تحتفظ بالقيمة الحالية للمعامل، وتضيفها إلى مجموعة، ثم تحدّثها بالعلاقة الضربية للحصول على المعامل التالي. وبما أن بنية التخزين تحفظ القيم الصحيحة المميزة فقط، فإن التكرارات الناتجة عن تناظر الصف أو عن تكرار القيم في صفوف أخرى تختفي تلقائيًا.

ترشيح القيم الخالية من المربعات وتجميع المجموع

بعد بناء المجموعة يمر التنفيذ على جميع القيم المخزنة. توجد في دالة الفحص حالة دفاعية لاختبار \(v=0\)، مع أن جميع معاملات ثنائية الحد هنا موجبة فعليًا. بعد ذلك تُستبعد مضاعفات \(4\)، ثم تُفحص المربعات الفردية حتى \(\sqrt{v}\)، ولا يُضاف إلى المجموع إلا العدد الذي لا يملك قاسمًا مربعًا. كما أن أحد التنفيذات يتحقق أولًا من قيمة الضبط الخاصة بأول 8 صفوف، وهي \(105\)، قبل الانتقال إلى الحالة الكاملة ذات 51 صفًا.

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

إذا عالجنا أول \(R\) صفوف، فإن عدد المواضع المولدة يساوي

$$\sum_{n=0}^{R-1}(n+1)=\frac{R(R+1)}{2},$$

ولذلك فإن مرحلة توليد الصفوف تكلف \(O(R^2)\). إذا رمزنا بعدد القيم المختلفة بعد إزالة التكرار بالرمز \(U\)، وبأكبر قيمة بينها بالرمز \(M\)، فإن مرحلة اختبار squarefree تكلف في أسوأ الأحوال \(O(U\sqrt{M})\) من عمليات القسمة التجريبية، لأن كل قيمة تُفحص بالقيم الفردية حتى \(\sqrt{v}\).

أما الذاكرة فهي \(O(U)\) لتخزين مجموعة المعاملات المختلفة. وفي المسألة الفعلية لدينا \(R=51\)، أي إن عدد المواضع المولدة لا يتجاوز 1326 موضعًا، كما أن أكبر المعاملات ما زالت ضمن مجال الأعداد الصحيحة ذات 64 بت براحة كبيرة. لذلك فإن هذا الأسلوب المباشر القائم على "التوليد ثم إزالة التكرار ثم الفحص" كافٍ تمامًا هنا.

هوامش ومراجع

  1. صفحة المسألة: https://projecteuler.net/problem=203
  2. مثلث باسكال: Wikipedia - Pascal's triangle
  3. معامل ثنائي الحدين: Wikipedia - Binomial coefficient
  4. عدد خالٍ من المربعات: Wikipedia - Square-free integer