Problem Summary

We count monotone lattice paths from \((0,0)\) to \((n,n)\), where each step is either one unit right or one unit up. A path is admissible if it never visits any forbidden grid point.

In the implementations, the forbidden points are exactly the interior square-coordinate points

$$F_n=\{(a^2,b^2): 1 \le a,b \le \lfloor \sqrt{n}\rfloor,\ \exists c \in \mathbb{Z}_{>0}: a^2+b^2=c^2\}.$$

The final answer is the number of admissible paths modulo \(10^9+7\).

Mathematical Approach

Step 1: Count paths between two comparable points

If \((x_1,y_1)\) and \((x_2,y_2)\) satisfy \(x_1 \le x_2\) and \(y_1 \le y_2\), then any monotone path from the first point to the second point must use exactly \(x_2-x_1\) right moves and \(y_2-y_1\) up moves. Hence the number of such paths is

$$\binom{(x_2-x_1)+(y_2-y_1)}{x_2-x_1}.$$

In particular, without any forbidden points, the total number of paths from \((0,0)\) to \((n,n)\) is

$$\binom{2n}{n}.$$

Step 2: Describe the forbidden set

Only points with both coordinates at most \(n\) can matter, so it is enough to enumerate \(a,b \le \lfloor \sqrt{n}\rfloor\). The condition \(a^2+b^2=c^2\) means that \((a,b,c)\) forms a Pythagorean triple, and each such pair produces a forbidden point \((a^2,b^2)\).

After sorting the forbidden points lexicographically, write them as

$$P_1=(x_1,y_1),\ P_2=(x_2,y_2),\ \dots,\ P_m=(x_m,y_m).$$

This ordering is compatible with monotone movement: if a path can go from \(P_j\) to \(P_i\), then necessarily \(x_j \le x_i\) and \(y_j \le y_i\), which implies \(j \lt i\) after lexicographic sorting.

Step 3: Inclusion-exclusion by the first forbidden point

For each forbidden point \(P_i\), let \(B_i\) be the number of monotone paths from \((0,0)\) to \(P_i\) whose first forbidden point is exactly \(P_i\). Start from the unrestricted count

$$\binom{x_i+y_i}{x_i}.$$

If a path reaches an earlier forbidden point \(P_j\) first and later continues to \(P_i\), then the number of such paths is

$$B_j \binom{(x_i-x_j)+(y_i-y_j)}{x_i-x_j},$$

provided \(x_j \le x_i\) and \(y_j \le y_i\). Therefore

$$B_i=\binom{x_i+y_i}{x_i}-\sum_{\substack{j \lt i \\ x_j \le x_i \\ y_j \le y_i}} B_j \binom{(x_i-x_j)+(y_i-y_j)}{x_i-x_j} \pmod{10^9+7}.$$

This dynamic program is a topological inclusion-exclusion on the partial order induced by coordinate-wise comparison.

Every inadmissible path from \((0,0)\) to \((n,n)\) has a unique first forbidden point, so after all \(B_i\) are known we subtract the bad paths by that first hit:

$$A(n)=\binom{2n}{n}-\sum_{i=1}^{m} B_i \binom{(n-x_i)+(n-y_i)}{n-x_i} \pmod{10^9+7}.$$

This is exactly the recurrence used in the implementations.

Step 4: Worked examples from the checkpoints

For \(n=5\), there are no forbidden points because the only possible square coordinates are \(1\) and \(4\), and none of the sums \(1+1\), \(1+4\), \(4+1\), \(4+4\) is a square. Hence

$$A(5)=\binom{10}{5}=252.$$

For \(n=16\), the forbidden points are \((9,16)\) and \((16,9)\), coming from \(3^2+4^2=5^2\) and \(4^2+3^2=5^2\). The unrestricted count is

$$\binom{32}{16}=601080390.$$

Each forbidden point receives

$$\binom{9+16}{9}=\binom{25}{9}=2042975$$

paths from the origin. Neither forbidden point dominates the other, so no path can pass through both. Therefore

$$A(16)=\binom{32}{16}-2\binom{25}{9}=596994440,$$

which matches the checkpoint value used by the implementations.

Step 5: Fast modular binomial coefficients

All binomial coefficients are evaluated modulo the prime

$$M=10^9+7.$$

The implementations precompute factorials and inverse factorials up to \(2n\), so every combination query becomes

$$\binom{N}{R}\equiv N! \cdot (R!)^{-1} \cdot ((N-R)!)^{-1} \pmod{M}.$$

The inverse factorials are derived using Fermat's little theorem:

$$a^{-1}\equiv a^{M-2}\pmod{M}, \qquad a \not\equiv 0 \pmod{M}.$$

After this preprocessing, each path-count query is \(O(1)\).

How the Code Works

The C++, Python, and Java implementations follow the same structure. They first build a fast square-membership structure up to \(2n\), enumerate every forbidden point \((a^2,b^2)\) inside the \(n \times n\) grid, sort the resulting list, and remove duplicates. Next they precompute factorials and inverse factorials so that any binomial coefficient needed by the path formulas can be answered in constant time modulo \(10^9+7\).

Once those tables are ready, the implementation scans the forbidden points in sorted order and computes the number of paths whose first forbidden point is each obstacle. The final admissible count is obtained by subtracting all bad-path contributions from the unrestricted total \(\binom{2n}{n}\).

Complexity Analysis

Let \(m\) be the number of forbidden points. Enumerating candidate square pairs takes \(O(n)\) time because both \(a\) and \(b\) range up to \(\lfloor \sqrt{n}\rfloor\). Precomputing factorials and inverse factorials up to \(2n\) also takes \(O(n)\) time and \(O(n)\) memory. The dynamic program compares each forbidden point with all earlier ones, so it costs \(O(m^2)\) time and \(O(m)\) additional memory. Overall, the algorithm runs in \(O(n+m^2)\) time and uses \(O(n+m)\) memory.

Footnotes and References

  1. Problem page: https://projecteuler.net/problem=408
  2. Lattice path counting: Wikipedia — Lattice path
  3. Binomial coefficients: Wikipedia — Binomial coefficient
  4. Fermat's little theorem: Wikipedia — Fermat's little theorem
  5. Pythagorean triples: Wikipedia — Pythagorean triple

Problemzusammenfassung

Gesucht ist die Anzahl monotoner Gitterpfade von \((0,0)\) nach \((n,n)\), wobei jeder Schritt entweder nach rechts oder nach oben geht. Ein Pfad ist genau dann zulässig, wenn er keinen verbotenen Gitterpunkt betritt.

In den Implementierungen sind die verbotenen Punkte genau die inneren Punkte mit quadratischen Koordinaten

$$F_n=\{(a^2,b^2): 1 \le a,b \le \lfloor \sqrt{n}\rfloor,\ \exists c \in \mathbb{Z}_{>0}: a^2+b^2=c^2\}.$$

Das Ergebnis wird modulo \(10^9+7\) ausgegeben.

Mathematischer Ansatz

Schritt 1: Pfade zwischen zwei vergleichbaren Punkten zählen

Seien \((x_1,y_1)\) und \((x_2,y_2)\) mit \(x_1 \le x_2\) und \(y_1 \le y_2\) gegeben. Jeder monotone Pfad zwischen diesen Punkten enthält genau \(x_2-x_1\) Rechts-Schritte und \(y_2-y_1\) Hoch-Schritte. Daher gibt es

$$\binom{(x_2-x_1)+(y_2-y_1)}{x_2-x_1}$$

solche Pfade. Ohne Verbote folgt insbesondere

$$\binom{2n}{n}$$

als Gesamtzahl aller Pfade von \((0,0)\) nach \((n,n)\).

Schritt 2: Die verbotene Punktmenge beschreiben

Relevant sind nur Punkte mit Koordinaten höchstens \(n\), also genügt es, \(a,b \le \lfloor \sqrt{n}\rfloor\) zu betrachten. Die Bedingung \(a^2+b^2=c^2\) bedeutet, dass \((a,b,c)\) ein pythagoreisches Tripel bildet. Jedes solche Paar erzeugt einen verbotenen Punkt \((a^2,b^2)\).

Nach dem Sortieren schreiben wir die verbotenen Punkte als

$$P_1=(x_1,y_1),\ P_2=(x_2,y_2),\ \dots,\ P_m=(x_m,y_m).$$

Diese Reihenfolge passt zur monotonen Bewegung: Wenn ein Pfad von \(P_j\) nach \(P_i\) gelangen kann, dann muss \(x_j \le x_i\) und \(y_j \le y_i\) gelten, also erscheint \(P_j\) in der lexikographischen Ordnung vor \(P_i\).

Schritt 3: Inklusion-Exklusion über den ersten verbotenen Punkt

Für jeden verbotenen Punkt \(P_i\) sei \(B_i\) die Anzahl der monotonen Pfade von \((0,0)\) nach \(P_i\), deren erster verbotener Punkt genau \(P_i\) ist. Zunächst gibt es insgesamt

$$\binom{x_i+y_i}{x_i}$$

Pfade zum Punkt \(P_i\). Wenn ein Pfad aber zuerst einen früheren verbotenen Punkt \(P_j\) trifft und danach zu \(P_i\) weiterläuft, dann gibt es davon

$$B_j \binom{(x_i-x_j)+(y_i-y_j)}{x_i-x_j}$$

unter der Voraussetzung \(x_j \le x_i\) und \(y_j \le y_i\). Also gilt die Rekurrenz

$$B_i=\binom{x_i+y_i}{x_i}-\sum_{\substack{j \lt i \\ x_j \le x_i \\ y_j \le y_i}} B_j \binom{(x_i-x_j)+(y_i-y_j)}{x_i-x_j} \pmod{10^9+7}.$$

Das ist ein dynamisches Programm in topologischer Ordnung der durch Koordinatenvergleich definierten Halbordnung.

Jeder unzulässige Pfad nach \((n,n)\) besitzt genau einen ersten verbotenen Punkt. Deshalb ist die gesuchte Anzahl

$$A(n)=\binom{2n}{n}-\sum_{i=1}^{m} B_i \binom{(n-x_i)+(n-y_i)}{n-x_i} \pmod{10^9+7}.$$

Schritt 4: Durchgerechnete Beispiele aus den Kontrollwerten

Für \(n=5\) gibt es keine verbotenen Punkte, denn die einzigen quadratischen Koordinaten \(1\) und \(4\) liefern nur die Summen \(1+1\), \(1+4\), \(4+1\), \(4+4\), und keine davon ist ein Quadrat. Daher

$$A(5)=\binom{10}{5}=252.$$

Für \(n=16\) sind die verbotenen Punkte \((9,16)\) und \((16,9)\), entsprechend \(3^2+4^2=5^2\) und \(4^2+3^2=5^2\). Ohne Verbote gibt es

$$\binom{32}{16}=601080390$$

Pfade. Zu jedem der beiden verbotenen Punkte führen

$$\binom{9+16}{9}=\binom{25}{9}=2042975$$

Pfade vom Ursprung. Keiner dieser Punkte liegt koordinatenweise vor dem anderen, also kann kein monotoner Pfad beide besuchen. Somit

$$A(16)=\binom{32}{16}-2\binom{25}{9}=596994440,$$

genau der Kontrollwert der Implementierungen.

Schritt 5: Schnelle modulare Binomialkoeffizienten

Alle Kombinationen werden modulo der Primzahl

$$M=10^9+7$$

berechnet. Dazu werden Fakultäten und inverse Fakultäten bis \(2n\) vorab bestimmt, sodass

$$\binom{N}{R}\equiv N! \cdot (R!)^{-1} \cdot ((N-R)!)^{-1} \pmod{M}$$

gilt. Die Inversen folgen aus dem kleinen Satz von Fermat:

$$a^{-1}\equiv a^{M-2}\pmod{M}, \qquad a \not\equiv 0 \pmod{M}.$$

Nach dieser Vorverarbeitung ist jede einzelne Kombinationsabfrage \(O(1)\).

Wie der Code arbeitet

Die C++-, Python- und Java-Implementierungen verwenden denselben Ablauf. Zuerst wird eine schnelle Struktur aufgebaut, die für alle Werte bis \(2n\) testet, ob sie Quadrate sind. Damit werden alle verbotenen Punkte \((a^2,b^2)\) innerhalb des \(n \times n\)-Gitters erzeugt, sortiert und gegebenenfalls dedupliziert. Danach werden Fakultäts- und Inversfakultätstabellen erzeugt, damit jeder benötigte Binomialkoeffizient in konstanter Zeit modulo \(10^9+7\) berechnet werden kann.

Anschließend verarbeitet die Implementierung die verbotenen Punkte in sortierter Reihenfolge, berechnet für jeden Punkt die Anzahl der Pfade mit genau diesem ersten verbotenen Treffer und subtrahiert schließlich alle unzulässigen Beiträge von der Gesamtzahl \(\binom{2n}{n}\).

Komplexitätsanalyse

Sei \(m\) die Anzahl der verbotenen Punkte. Das Durchlaufen aller Kandidatenpaare \((a,b)\) benötigt \(O(n)\) Zeit, weil sowohl \(a\) als auch \(b\) bis \(\lfloor \sqrt{n}\rfloor\) laufen. Die Vorberechnung von Fakultäten und inversen Fakultäten bis \(2n\) kostet ebenfalls \(O(n)\) Zeit und \(O(n)\) Speicher. Das dynamische Programm vergleicht jeden verbotenen Punkt mit allen früheren Punkten und benötigt daher \(O(m^2)\) Zeit sowie \(O(m)\) zusätzlichen Speicher. Insgesamt ergibt sich \(O(n+m^2)\) Zeit und \(O(n+m)\) Speicher.

Fußnoten und Quellen

  1. Problemseite: https://projecteuler.net/problem=408
  2. Gitterpfade: Wikipedia — Gitterweg
  3. Binomialkoeffizient: Wikipedia — Binomialkoeffizient
  4. Kleiner Satz von Fermat: Wikipedia — Kleiner Satz von Fermat
  5. Pythagoreisches Tripel: Wikipedia — Pythagoreisches Tripel

Problem Özeti

\((0,0)\) noktasından \((n,n)\) noktasına yalnız sağa veya yukarı adımlarla giden monoton kafes yollarının sayısı istenir. Bir yol, yasaklı bir noktadan hiç geçmiyorsa admissible kabul edilir.

Uygulamalarda yasaklı noktalar tam olarak şu iç noktalardır:

$$F_n=\{(a^2,b^2): 1 \le a,b \le \lfloor \sqrt{n}\rfloor,\ \exists c \in \mathbb{Z}_{>0}: a^2+b^2=c^2\}.$$

Sonuç \(10^9+7\) modunda hesaplanır.

Matematiksel Yaklaşım

Adım 1: Karşılaştırılabilir iki nokta arasındaki yol sayısı

\((x_1,y_1)\) ve \((x_2,y_2)\) için \(x_1 \le x_2\) ve \(y_1 \le y_2\) olsun. Bir monoton yol tam olarak \(x_2-x_1\) adet sağ adımı ve \(y_2-y_1\) adet yukarı adımı içerir. Bu yüzden yol sayısı

$$\binom{(x_2-x_1)+(y_2-y_1)}{x_2-x_1}$$

olur. Özellikle hiçbir yasak yoksa \((0,0)\) ile \((n,n)\) arasındaki toplam yol sayısı

$$\binom{2n}{n}$$

dir.

Adım 2: Yasaklı nokta kümesini tanımlamak

Yalnız koordinatları \(n\)'i geçmeyen noktalar etkili olabilir; bu nedenle \(a,b \le \lfloor \sqrt{n}\rfloor\) taraması yeterlidir. \(a^2+b^2=c^2\) koşulu, \((a,b,c)\) üçlüsünün Pisagor üçlüsü olması demektir. Böyle her çift, \((a^2,b^2)\) biçiminde bir yasaklı nokta üretir.

Sıralamadan sonra bu noktaları

$$P_1=(x_1,y_1),\ P_2=(x_2,y_2),\ \dots,\ P_m=(x_m,y_m)$$

şeklinde yazalım. Bu leksikografik sıra monoton yürüyüşle uyumludur: Bir yol \(P_j\)'den \(P_i\)'ye gidebiliyorsa mutlaka \(x_j \le x_i\) ve \(y_j \le y_i\) olmalıdır; dolayısıyla \(P_j\), sıralamada \(P_i\)'den önce gelir.

Adım 3: İlk yasaklı noktaya göre dahil etme-çıkarma

Her yasaklı nokta \(P_i\) için \(B_i\), \((0,0)\)'dan \(P_i\)'ye giden ve karşılaştığı ilk yasaklı nokta tam olarak \(P_i\) olan yol sayısı olsun. Önce sınırsız sayıyı alırız:

$$\binom{x_i+y_i}{x_i}.$$

Eğer bir yol önce daha erken bir yasaklı nokta \(P_j\)'ye uğrayıp sonra \(P_i\)'ye ulaşıyorsa, bu tür yolların sayısı

$$B_j \binom{(x_i-x_j)+(y_i-y_j)}{x_i-x_j}$$

olur; burada \(x_j \le x_i\) ve \(y_j \le y_i\) gereklidir. Böylece rekürans

$$B_i=\binom{x_i+y_i}{x_i}-\sum_{\substack{j \lt i \\ x_j \le x_i \\ y_j \le y_i}} B_j \binom{(x_i-x_j)+(y_i-y_j)}{x_i-x_j} \pmod{10^9+7}$$

şeklini alır. Bu, koordinatlara göre tanımlanan kısmi sıralama üzerinde çalışan bir dinamik programdır.

\((n,n)\)'ye giden her geçersiz yolun tek bir ilk yasaklı noktası vardır. Bu nedenle nihai cevap

$$A(n)=\binom{2n}{n}-\sum_{i=1}^{m} B_i \binom{(n-x_i)+(n-y_i)}{n-x_i} \pmod{10^9+7}$$

olur.

Adım 4: Kontrol örnekleri

\(n=5\) için yasaklı nokta yoktur. Çünkü olası kare koordinatlar yalnızca \(1\) ve \(4\) tür; \(1+1\), \(1+4\), \(4+1\), \(4+4\) toplamlarının hiçbiri tam kare değildir. Dolayısıyla

$$A(5)=\binom{10}{5}=252.$$

\(n=16\) için yasaklı noktalar \((9,16)\) ve \((16,9)\) olur; bunlar \(3^2+4^2=5^2\) ve ters sıradaki aynı kimlikten gelir. Yasaksız toplam

$$\binom{32}{16}=601080390$$

dır. Her yasaklı noktaya başlangıçtan

$$\binom{9+16}{9}=\binom{25}{9}=2042975$$

yol gider. Bu iki nokta birbirini koordinat bazında kapsamamadığı için aynı yol üzerinde ikisi birden bulunamaz. O halde

$$A(16)=\binom{32}{16}-2\binom{25}{9}=596994440,$$

ki bu da uygulamalardaki kontrol değeriyle aynıdır.

Adım 5: Hızlı modüler binom katsayıları

Tüm kombinasyonlar asal sayı

$$M=10^9+7$$

modunda hesaplanır. Bunun için \(2n\)'e kadar faktöriyeller ve ters faktöriyeller önceden hazırlanır:

$$\binom{N}{R}\equiv N! \cdot (R!)^{-1} \cdot ((N-R)!)^{-1} \pmod{M}.$$

Tersler Fermat'nın küçük teoremi ile bulunur:

$$a^{-1}\equiv a^{M-2}\pmod{M}, \qquad a \not\equiv 0 \pmod{M}.$$

Böylece her binom sorgusu sabit zamanda cevaplanır.

Kodun Çalışma Mantığı

C++, Python ve Java implementasyonları aynı hattı izler. Önce \(2n\)'e kadar hangi sayıların kare olduğunu hızlıca sorgulayabilen bir yapı kurulur. Ardından \(n \times n\) kare içindeki tüm \((a^2,b^2)\) adayları taranır, Pisagor koşulunu sağlayanlar yasaklı nokta listesine eklenir, liste sıralanır ve tekilleştirilir. Sonra faktöriyel ve ters faktöriyel tabloları hazırlanarak bütün binom katsayıları \(10^9+7\) modunda sabit zamanda hesaplanabilir hale getirilir.

Bu hazırlıklardan sonra uygulama yasaklı noktaları sıralı biçimde işler, her nokta için ilk yasaklı temas sayısını hesaplar ve en sonunda tüm geçersiz katkıları \(\binom{2n}{n}\) toplamından çıkarır.

Karmaşıklık Analizi

\(m\) yasaklı nokta sayısı olsun. Aday \((a,b)\) çiftlerini taramak \(O(n)\) zaman alır; çünkü hem \(a\) hem \(b\), \(\lfloor \sqrt{n}\rfloor\) sınırına kadar gider. \(2n\)'e kadar faktöriyel ve ters faktöriyel ön hesapları da \(O(n)\) zaman ve \(O(n)\) bellek ister. Dinamik program her yasaklı noktayı önceki bütün yasaklı noktalarla karşılaştırdığı için \(O(m^2)\) zaman ve \(O(m)\) ek bellek kullanır. Toplam karmaşıklık \(O(n+m^2)\) zaman ve \(O(n+m)\) bellek olur.

Dipnotlar ve Kaynakça

  1. Problem sayfası: https://projecteuler.net/problem=408
  2. Kafes yolu sayımı: Wikipedia — Kafes yolu
  3. Binom katsayısı: Wikipedia — Binom katsayısı
  4. Fermat'nın küçük teoremi: Wikipedia — Fermat'nın küçük teoremi
  5. Pisagor üçlüleri: Wikipedia — Pisagor üçlüsü

Resumen del Problema

Debemos contar los caminos monótonos desde \((0,0)\) hasta \((n,n)\), donde cada paso es una unidad a la derecha o una unidad hacia arriba. Un camino es admisible si nunca pasa por un punto prohibido.

En las implementaciones, los puntos prohibidos son exactamente los puntos interiores con coordenadas cuadradas

$$F_n=\{(a^2,b^2): 1 \le a,b \le \lfloor \sqrt{n}\rfloor,\ \exists c \in \mathbb{Z}_{>0}: a^2+b^2=c^2\}.$$

La respuesta final se calcula módulo \(10^9+7\).

Enfoque Matemático

Paso 1: Contar caminos entre dos puntos comparables

Si \((x_1,y_1)\) y \((x_2,y_2)\) cumplen \(x_1 \le x_2\) y \(y_1 \le y_2\), cualquier camino monótono entre ellos contiene exactamente \(x_2-x_1\) movimientos a la derecha y \(y_2-y_1\) movimientos hacia arriba. Por tanto, el número de caminos es

$$\binom{(x_2-x_1)+(y_2-y_1)}{x_2-x_1}.$$

En particular, sin obstáculos, el número total de caminos desde el origen hasta \((n,n)\) es

$$\binom{2n}{n}.$$

Paso 2: Describir el conjunto prohibido

Solo importan los puntos con coordenadas a lo sumo \(n\), así que basta enumerar \(a,b \le \lfloor \sqrt{n}\rfloor\). La condición \(a^2+b^2=c^2\) significa que \((a,b,c)\) forma una terna pitagórica, y cada una de esas parejas produce un punto prohibido \((a^2,b^2)\).

Después de ordenar los puntos prohibidos, escribimos

$$P_1=(x_1,y_1),\ P_2=(x_2,y_2),\ \dots,\ P_m=(x_m,y_m).$$

Este orden es compatible con el movimiento monótono: si un camino puede ir de \(P_j\) a \(P_i\), necesariamente se cumple \(x_j \le x_i\) y \(y_j \le y_i\), así que \(P_j\) aparece antes que \(P_i\) en el orden lexicográfico.

Paso 3: Inclusión-exclusión según el primer punto prohibido

Para cada punto prohibido \(P_i\), sea \(B_i\) el número de caminos desde \((0,0)\) hasta \(P_i\) cuyo primer punto prohibido es exactamente \(P_i\). El número total de caminos hacia \(P_i\) sin restricciones es

$$\binom{x_i+y_i}{x_i}.$$

Si un camino toca primero un punto prohibido anterior \(P_j\) y después continúa hasta \(P_i\), entonces hay

$$B_j \binom{(x_i-x_j)+(y_i-y_j)}{x_i-x_j}$$

caminos de ese tipo, siempre que \(x_j \le x_i\) y \(y_j \le y_i\). Por ello

$$B_i=\binom{x_i+y_i}{x_i}-\sum_{\substack{j \lt i \\ x_j \le x_i \\ y_j \le y_i}} B_j \binom{(x_i-x_j)+(y_i-y_j)}{x_i-x_j} \pmod{10^9+7}.$$

Esto es una DP de inclusión-exclusión sobre el orden parcial dado por la comparación coordenada a coordenada.

Cada camino no admisible hasta \((n,n)\) tiene un único primer punto prohibido. Entonces

$$A(n)=\binom{2n}{n}-\sum_{i=1}^{m} B_i \binom{(n-x_i)+(n-y_i)}{n-x_i} \pmod{10^9+7}.$$

Paso 4: Ejemplos de los valores de comprobación

Para \(n=5\) no hay puntos prohibidos, porque las únicas coordenadas cuadradas posibles son \(1\) y \(4\), y ninguna de las sumas \(1+1\), \(1+4\), \(4+1\), \(4+4\) es un cuadrado. Por tanto

$$A(5)=\binom{10}{5}=252.$$

Para \(n=16\), los puntos prohibidos son \((9,16)\) y \((16,9)\), provenientes de \(3^2+4^2=5^2\) y de la misma identidad con los catetos intercambiados. El total sin restricciones es

$$\binom{32}{16}=601080390.$$

Cada uno de esos puntos recibe

$$\binom{9+16}{9}=\binom{25}{9}=2042975$$

caminos desde el origen. Ninguno domina al otro, así que un camino monótono no puede pasar por ambos. En consecuencia,

$$A(16)=\binom{32}{16}-2\binom{25}{9}=596994440,$$

que coincide con el valor de verificación usado por las implementaciones.

Paso 5: Coeficientes binomiales modulares rápidos

Todos los coeficientes binomiales se calculan módulo el primo

$$M=10^9+7.$$

Las implementaciones precalculan factoriales e inversos factoriales hasta \(2n\), de modo que

$$\binom{N}{R}\equiv N! \cdot (R!)^{-1} \cdot ((N-R)!)^{-1} \pmod{M}.$$

Los inversos se obtienen con el pequeño teorema de Fermat:

$$a^{-1}\equiv a^{M-2}\pmod{M}, \qquad a \not\equiv 0 \pmod{M}.$$

Después de esta preparación, cada consulta de combinación cuesta \(O(1)\).

Cómo Funciona el Código

Las implementaciones en C++, Python y Java siguen el mismo esquema. Primero construyen una estructura rápida para comprobar si un número hasta \(2n\) es cuadrado. Luego enumeran todos los puntos \((a^2,b^2)\) dentro del cuadrado \(n \times n\), conservan solo los que satisfacen la condición pitagórica, los ordenan y eliminan duplicados. Después precalculan factoriales e inversos factoriales para responder todas las combinaciones necesarias en tiempo constante módulo \(10^9+7\).

Con esas tablas listas, la implementación recorre los puntos prohibidos en orden, calcula para cada uno cuántos caminos lo tienen como primer punto prohibido y finalmente resta todas esas contribuciones del total libre \(\binom{2n}{n}\).

Análisis de Complejidad

Sea \(m\) el número de puntos prohibidos. Enumerar los pares candidatos \((a,b)\) cuesta \(O(n)\) tiempo, porque tanto \(a\) como \(b\) llegan hasta \(\lfloor \sqrt{n}\rfloor\). El precálculo de factoriales e inversos factoriales hasta \(2n\) también cuesta \(O(n)\) tiempo y \(O(n)\) memoria. La DP compara cada punto prohibido con todos los anteriores, así que requiere \(O(m^2)\) tiempo y \(O(m)\) memoria adicional. En conjunto, el algoritmo usa \(O(n+m^2)\) tiempo y \(O(n+m)\) memoria.

Notas y Referencias

  1. Página del problema: https://projecteuler.net/problem=408
  2. Caminos en retículas: Wikipedia — Camino de retícula
  3. Coeficiente binomial: Wikipedia — Coeficiente binomial
  4. Pequeño teorema de Fermat: Wikipedia — Pequeño teorema de Fermat
  5. Terna pitagórica: Wikipedia — Terna pitagórica

问题概述

题目要求统计从 \((0,0)\) 到 \((n,n)\) 的单调格点路径数量,每一步只能向右或向上。若一条路径从未经过任何禁点,则称其为 admissible path。

在这些实现中,禁点恰好是所有内部的平方坐标点

$$F_n=\{(a^2,b^2): 1 \le a,b \le \lfloor \sqrt{n}\rfloor,\ \exists c \in \mathbb{Z}_{>0}: a^2+b^2=c^2\}$$

最终答案对 \(10^9+7\) 取模。

数学方法

步骤 1:计算两个可比较点之间的路径数

若 \((x_1,y_1)\) 与 \((x_2,y_2)\) 满足 \(x_1 \le x_2\) 且 \(y_1 \le y_2\),那么从前者到后者的单调路径必须恰好走 \(x_2-x_1\) 次向右和 \(y_2-y_1\) 次向上。因此路径条数为

$$\binom{(x_2-x_1)+(y_2-y_1)}{x_2-x_1}$$

特别地,不考虑禁点时,从原点到终点的总路径数是

$$\binom{2n}{n}$$

步骤 2:描述禁点集合

只有坐标不超过 \(n\) 的点才可能影响答案,所以只需枚举 \(a,b \le \lfloor \sqrt{n}\rfloor\)。条件 \(a^2+b^2=c^2\) 表示 \((a,b,c)\) 构成勾股三元组,每一组都会产生一个禁点 \((a^2,b^2)\)。

将所有禁点按字典序排序后记为

$$P_1=(x_1,y_1),\ P_2=(x_2,y_2),\ \dots,\ P_m=(x_m,y_m)$$

这个顺序与单调移动相容。如果一条路径能够从 \(P_j\) 走到 \(P_i\),那么必有 \(x_j \le x_i\) 且 \(y_j \le y_i\),于是 \(P_j\) 一定排在 \(P_i\) 之前。

步骤 3:按“第一个禁点”做容斥型 DP

对每个禁点 \(P_i\),定义 \(B_i\) 为从 \((0,0)\) 到 \(P_i\) 的路径中,“第一次碰到的禁点正好是 \(P_i\)” 的路径数。先看不受限制的总数:

$$\binom{x_i+y_i}{x_i}$$

如果某条路径先到达更早的禁点 \(P_j\),再走到 \(P_i\),则这样的路径数为

$$B_j \binom{(x_i-x_j)+(y_i-y_j)}{x_i-x_j}$$

其中需要满足 \(x_j \le x_i\) 且 \(y_j \le y_i\)。因此有递推式

$$B_i=\binom{x_i+y_i}{x_i}-\sum_{\substack{j \lt i \\ x_j \le x_i \\ y_j \le y_i}} B_j \binom{(x_i-x_j)+(y_i-y_j)}{x_i-x_j} \pmod{10^9+7}$$

这可以看作是按照坐标偏序进行的拓扑式容斥动态规划。

每一条不合法的终点路径都有唯一的“第一个禁点”,所以最终答案为

$$A(n)=\binom{2n}{n}-\sum_{i=1}^{m} B_i \binom{(n-x_i)+(n-y_i)}{n-x_i} \pmod{10^9+7}$$

步骤 4:用检查点做具体例子

当 \(n=5\) 时,没有禁点。因为可能的平方坐标只有 \(1\) 和 \(4\),而 \(1+1\)、\(1+4\)、\(4+1\)、\(4+4\) 都不是完全平方数,所以

$$A(5)=\binom{10}{5}=252$$

当 \(n=16\) 时,禁点只有 \((9,16)\) 和 \((16,9)\),它们来自 \(3^2+4^2=5^2\) 及其交换形式。不受限制的总路径数为

$$\binom{32}{16}=601080390$$

从原点到每个禁点的路径数都是

$$\binom{9+16}{9}=\binom{25}{9}=2042975$$

这两个禁点互不支配,因此同一条单调路径不可能同时经过它们。于是

$$A(16)=\binom{32}{16}-2\binom{25}{9}=596994440,$$

这与实现中的检查值一致。

步骤 5:快速模组合数

所有组合数都在素数模

$$M=10^9+7$$

下计算。实现会预处理到 \(2n\) 的阶乘和逆阶乘,因此

$$\binom{N}{R}\equiv N! \cdot (R!)^{-1} \cdot ((N-R)!)^{-1} \pmod{M}$$

逆元利用费马小定理得到:

$$a^{-1}\equiv a^{M-2}\pmod{M}, \qquad a \not\equiv 0 \pmod{M}$$

完成预处理后,每次组合数查询都是 \(O(1)\)。

代码如何工作

C++、Python 和 Java 实现遵循同一条主线。首先建立一个能够快速判断某个数在 \(2n\) 以内是否为平方数的结构。然后枚举 \(n \times n\) 方格中的所有 \((a^2,b^2)\) 候选点,只保留满足勾股条件的点,并对它们排序去重。接着预处理阶乘和逆阶乘表,以便所有路径公式中的组合数都能在 \(10^9+7\) 模下常数时间求出。

准备完成后,程序按顺序扫描禁点,计算每个禁点作为“第一个禁点”时对应的路径数,最后把这些不合法贡献从自由总数 \(\binom{2n}{n}\) 中减掉。

复杂度分析

设禁点个数为 \(m\)。枚举候选对 \((a,b)\) 的时间为 \(O(n)\),因为 \(a\) 与 \(b\) 都只需遍历到 \(\lfloor \sqrt{n}\rfloor\)。预处理到 \(2n\) 的阶乘与逆阶乘需要 \(O(n)\) 时间和 \(O(n)\) 空间。动态规划部分会把每个禁点与之前所有禁点比较,因此需要 \(O(m^2)\) 时间和 \(O(m)\) 的额外空间。总复杂度为 \(O(n+m^2)\) 时间与 \(O(n+m)\) 空间。

参考资料

  1. 题目页面: https://projecteuler.net/problem=408
  2. 格点路径: Wikipedia — 格路径
  3. 二项式系数: Wikipedia — 二项式系数
  4. 费马小定理: Wikipedia — 费马小定理
  5. 勾股数: Wikipedia — 勾股数

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

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

В используемых реализациях запрещенными являются ровно внутренние точки с квадратными координатами

$$F_n=\{(a^2,b^2): 1 \le a,b \le \lfloor \sqrt{n}\rfloor,\ \exists c \in \mathbb{Z}_{>0}: a^2+b^2=c^2\}.$$

Ответ требуется по модулю \(10^9+7\).

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

Шаг 1: Число путей между двумя сравнимыми точками

Пусть \((x_1,y_1)\) и \((x_2,y_2)\) удовлетворяют условиям \(x_1 \le x_2\) и \(y_1 \le y_2\). Тогда любой монотонный путь между ними содержит ровно \(x_2-x_1\) шагов вправо и \(y_2-y_1\) шагов вверх. Следовательно, число таких путей равно

$$\binom{(x_2-x_1)+(y_2-y_1)}{x_2-x_1}.$$

В частности, без каких-либо запретов число путей из начала в \((n,n)\) равно

$$\binom{2n}{n}.$$

Шаг 2: Описание множества запрещенных точек

Имеют значение только точки с координатами не больше \(n\), поэтому достаточно перебрать \(a,b \le \lfloor \sqrt{n}\rfloor\). Условие \(a^2+b^2=c^2\) означает, что \((a,b,c)\) образует пифагорову тройку, а каждая такая пара дает запрещенную точку \((a^2,b^2)\).

После сортировки обозначим запрещенные точки так:

$$P_1=(x_1,y_1),\ P_2=(x_2,y_2),\ \dots,\ P_m=(x_m,y_m).$$

Этот порядок согласован с монотонным движением: если путь может пройти из \(P_j\) в \(P_i\), то обязательно \(x_j \le x_i\) и \(y_j \le y_i\), а значит, \(P_j\) стоит раньше \(P_i\) в лексикографическом порядке.

Шаг 3: Включения-исключения по первой запрещенной точке

Для каждой запрещенной точки \(P_i\) введем \(B_i\): это число путей из \((0,0)\) в \(P_i\), у которых первой запрещенной точкой является именно \(P_i\). Полное число путей в \(P_i\) без ограничений равно

$$\binom{x_i+y_i}{x_i}.$$

Если путь сначала попадает в более раннюю запрещенную точку \(P_j\), а затем идет в \(P_i\), то число таких путей равно

$$B_j \binom{(x_i-x_j)+(y_i-y_j)}{x_i-x_j}$$

при условиях \(x_j \le x_i\) и \(y_j \le y_i\). Поэтому получаем рекуррентную формулу

$$B_i=\binom{x_i+y_i}{x_i}-\sum_{\substack{j \lt i \\ x_j \le x_i \\ y_j \le y_i}} B_j \binom{(x_i-x_j)+(y_i-y_j)}{x_i-x_j} \pmod{10^9+7}.$$

Это динамика по топологическому порядку частичного порядка, заданного покоординатным сравнением.

У каждого недопустимого пути в \((n,n)\) есть единственная первая запрещенная точка, поэтому окончательная формула имеет вид

$$A(n)=\binom{2n}{n}-\sum_{i=1}^{m} B_i \binom{(n-x_i)+(n-y_i)}{n-x_i} \pmod{10^9+7}.$$

Шаг 4: Примеры из контрольных значений

Для \(n=5\) запрещенных точек нет, потому что возможные квадратные координаты только \(1\) и \(4\), а суммы \(1+1\), \(1+4\), \(4+1\), \(4+4\) не являются квадратами. Значит,

$$A(5)=\binom{10}{5}=252.$$

Для \(n=16\) запрещенные точки равны \((9,16)\) и \((16,9)\), что соответствует равенству \(3^2+4^2=5^2\) и перестановке катетов. Общее число путей без ограничений равно

$$\binom{32}{16}=601080390.$$

В каждую из этих точек из начала ведет

$$\binom{9+16}{9}=\binom{25}{9}=2042975$$

путей. Эти две точки несравнимы покоординатно, поэтому один монотонный путь не может пройти через обе. Следовательно,

$$A(16)=\binom{32}{16}-2\binom{25}{9}=596994440,$$

что совпадает с контрольным значением в реализациях.

Шаг 5: Быстрые биномиальные коэффициенты по модулю

Все биномиальные коэффициенты вычисляются по модулю простого числа

$$M=10^9+7.$$

Реализации заранее строят таблицы факториалов и обратных факториалов до \(2n\), после чего

$$\binom{N}{R}\equiv N! \cdot (R!)^{-1} \cdot ((N-R)!)^{-1} \pmod{M}.$$

Обратные элементы находятся по малой теореме Ферма:

$$a^{-1}\equiv a^{M-2}\pmod{M}, \qquad a \not\equiv 0 \pmod{M}.$$

После этой подготовки каждая комбинация вычисляется за \(O(1)\).

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

Реализации на C++, Python и Java устроены одинаково. Сначала строится быстрая структура для проверки, является ли число до \(2n\) квадратом. Затем перечисляются все кандидаты \((a^2,b^2)\) внутри квадрата \(n \times n\), сохраняются только точки, удовлетворяющие пифагорову условию, после чего список сортируется и очищается от повторов. Далее предвычисляются факториалы и обратные факториалы, чтобы все биномиальные коэффициенты в формулах путей получать за константное время по модулю \(10^9+7\).

После этого реализация проходит по запрещенным точкам в порядке сортировки, вычисляет число путей, для которых каждая точка является первой запрещенной, и в конце вычитает все недопустимые вклады из свободного количества \(\binom{2n}{n}\).

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

Пусть \(m\) обозначает число запрещенных точек. Перебор всех пар \((a,b)\) занимает \(O(n)\) времени, потому что и \(a\), и \(b\) изменяются до \(\lfloor \sqrt{n}\rfloor\). Предвычисление факториалов и обратных факториалов до \(2n\) также требует \(O(n)\) времени и \(O(n)\) памяти. Динамика сравнивает каждую запрещенную точку со всеми предыдущими, поэтому стоит \(O(m^2)\) по времени и \(O(m)\) по дополнительной памяти. В итоге полный алгоритм работает за \(O(n+m^2)\) и использует \(O(n+m)\) памяти.

Ссылки и литература

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

ملخص المسألة

نريد عدّ المسارات الأحادية من \((0,0)\) إلى \((n,n)\)، حيث تكون كل خطوة إما إلى اليمين أو إلى الأعلى. يكون المسار مقبولًا إذا لم يمر بأي نقطة ممنوعة.

في هذه الحلول، النقاط الممنوعة هي بالضبط النقاط الداخلية ذات الإحداثيات المربعة

$$F_n=\{(a^2,b^2): 1 \le a,b \le \lfloor \sqrt{n}\rfloor,\ \exists c \in \mathbb{Z}_{>0}: a^2+b^2=c^2\}.$$

ويحسب الجواب بترديد \(10^9+7\).

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

الخطوة 1: عدّ المسارات بين نقطتين قابلتين للمقارنة

إذا كانت \((x_1,y_1)\) و\((x_2,y_2)\) تحققان \(x_1 \le x_2\) و\(y_1 \le y_2\)، فإن أي مسار أحادي بينهما يجب أن يحتوي على \(x_2-x_1\) خطوات إلى اليمين و\(y_2-y_1\) خطوات إلى الأعلى. لذلك يكون عدد هذه المسارات

$$\binom{(x_2-x_1)+(y_2-y_1)}{x_2-x_1}.$$

وبصورة خاصة، من دون نقاط ممنوعة يكون عدد المسارات من البداية إلى \((n,n)\) هو

$$\binom{2n}{n}.$$

الخطوة 2: وصف مجموعة النقاط الممنوعة

النقاط الوحيدة المهمة هي التي لا تتجاوز إحداثياتها \(n\)، لذلك يكفي تعداد \(a,b \le \lfloor \sqrt{n}\rfloor\). الشرط \(a^2+b^2=c^2\) يعني أن \((a,b,c)\) يشكل ثلاثية فيثاغورس، وكل زوج من هذا النوع يولد نقطة ممنوعة هي \((a^2,b^2)\).

بعد ترتيب النقاط الممنوعة ترتيبًا معجميًا نكتبها بالشكل

$$P_1=(x_1,y_1),\ P_2=(x_2,y_2),\ \dots,\ P_m=(x_m,y_m).$$

هذا الترتيب منسجم مع الحركة الأحادية: إذا كان المسار يستطيع الانتقال من \(P_j\) إلى \(P_i\)، فلا بد أن \(x_j \le x_i\) و\(y_j \le y_i\)، وبالتالي يظهر \(P_j\) قبل \(P_i\) في الترتيب.

الخطوة 3: مبدأ الشمول والاستبعاد بحسب أول نقطة ممنوعة

لكل نقطة ممنوعة \(P_i\)، لتكن \(B_i\) عدد المسارات من \((0,0)\) إلى \(P_i\) التي تكون فيها أول نقطة ممنوعة يتم الوصول إليها هي \(P_i\) نفسها. العدد الكلي غير المقيّد للمسارات إلى \(P_i\) هو

$$\binom{x_i+y_i}{x_i}.$$

أما إذا مرّ المسار أولًا عبر نقطة ممنوعة سابقة \(P_j\) ثم واصل إلى \(P_i\)، فإن عدد هذه المسارات يساوي

$$B_j \binom{(x_i-x_j)+(y_i-y_j)}{x_i-x_j}$$

مع الشرط \(x_j \le x_i\) و\(y_j \le y_i\). لذلك نحصل على العلاقة

$$B_i=\binom{x_i+y_i}{x_i}-\sum_{\substack{j \lt i \\ x_j \le x_i \\ y_j \le y_i}} B_j \binom{(x_i-x_j)+(y_i-y_j)}{x_i-x_j} \pmod{10^9+7}.$$

وهذا برنامج ديناميكي يسير وفق ترتيب طوبولوجي للترتيب الجزئي المعطى بالمقارنة الإحداثية.

كل مسار غير مقبول إلى \((n,n)\) يملك نقطة ممنوعة أولى وحيدة، ومن ثم يكون الجواب النهائي

$$A(n)=\binom{2n}{n}-\sum_{i=1}^{m} B_i \binom{(n-x_i)+(n-y_i)}{n-x_i} \pmod{10^9+7}.$$

الخطوة 4: أمثلة محسوبة من نقاط التحقق

عندما \(n=5\) لا توجد أي نقطة ممنوعة، لأن الإحداثيات المربعة الممكنة هي \(1\) و\(4\) فقط، والمجاميع \(1+1\) و\(1+4\) و\(4+1\) و\(4+4\) ليست مربعات كاملة. لذلك

$$A(5)=\binom{10}{5}=252.$$

وعندما \(n=16\)، تكون النقطتان الممنوعتان هما \((9,16)\) و\((16,9)\)، الناتجتان من العلاقة \(3^2+4^2=5^2\) مع تبادل الضلعين. العدد الكلي للمسارات من دون قيود هو

$$\binom{32}{16}=601080390.$$

ويصل إلى كل نقطة ممنوعة من الأصل عدد مسارات مقداره

$$\binom{9+16}{9}=\binom{25}{9}=2042975.$$

هاتان النقطتان غير قابلتين للمقارنة إحداثيًا، لذا لا يمكن لمسار أحادي واحد أن يمر بهما معًا. ومن ثم

$$A(16)=\binom{32}{16}-2\binom{25}{9}=596994440,$$

وهو بالضبط مقدار التحقق المستخدم في الحلول.

الخطوة 5: معاملات ثنائية الحد السريعة بترديد أولي

جميع معاملات ثنائية الحد تحسب بترديد العدد الأولي

$$M=10^9+7.$$

تقوم الحلول بتهيئة المضروبات ومعكوسات المضروبات حتى \(2n\)، وبالتالي

$$\binom{N}{R}\equiv N! \cdot (R!)^{-1} \cdot ((N-R)!)^{-1} \pmod{M}.$$

أما المعكوسات فتستخرج من مبرهنة فيرما الصغرى:

$$a^{-1}\equiv a^{M-2}\pmod{M}, \qquad a \not\equiv 0 \pmod{M}.$$

بعد هذه التهيئة تصبح كل قيمة ثنائية الحد قابلة للحساب في زمن \(O(1)\).

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

تتبع تطبيقات C++ وPython وJava البنية نفسها. في البداية تُبنى بنية سريعة لاختبار ما إذا كان عدد ما حتى \(2n\) مربعًا كاملًا. بعد ذلك تُحصى جميع النقاط المرشحة \((a^2,b^2)\) داخل المربع \(n \times n\)، وتُحتفظ فقط بالنقاط التي تحقق شرط فيثاغورس، ثم تُرتب وتزال التكرارات منها. بعد ذلك تُحضّر جداول المضروبات ومعكوسات المضروبات حتى يمكن حساب كل معاملات ثنائية الحد المطلوبة في صيغ المسارات بزمن ثابت وبترديد \(10^9+7\).

بعد اكتمال هذه الجداول، تمرّ الشيفرة على النقاط الممنوعة بترتيبها، وتحسب لكل نقطة عدد المسارات التي تكون هذه النقطة أول نقطة ممنوعة فيها، ثم تطرح كل الإسهامات غير المقبولة من العدد الحر \(\binom{2n}{n}\).

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

ليكن \(m\) عدد النقاط الممنوعة. تعداد الأزواج المرشحة \((a,b)\) يحتاج إلى \(O(n)\) زمنًا، لأن كلًا من \(a\) و\(b\) يمتد حتى \(\lfloor \sqrt{n}\rfloor\). كما أن التهيئة المسبقة للمضروبات ومعكوسات المضروبات حتى \(2n\) تحتاج إلى \(O(n)\) زمنًا و\(O(n)\) ذاكرة. البرنامج الديناميكي يقارن كل نقطة ممنوعة بجميع النقاط السابقة، ولذلك يكلف \(O(m^2)\) زمنًا و\(O(m)\) ذاكرة إضافية. المحصلة النهائية هي \(O(n+m^2)\) زمنًا و\(O(n+m)\) ذاكرة.

مراجع ومصادر

  1. صفحة المسألة: https://projecteuler.net/problem=408
  2. المسارات الشبكية: Wikipedia — Lattice path
  3. معامل ثنائي الحد: Wikipedia — معامل ثنائي الحد
  4. مبرهنة فيرما الصغرى: Wikipedia — مبرهنة فيرما الصغرى
  5. ثلاثيات فيثاغورس: Wikipedia — ثلاثيات فيثاغورس