Problem Summary

Problem 638 asks for a sum of weighted monotone lattice-path counts. For nonnegative integers \(a\) and \(b\), the relevant quantity is

$$C(a,b,q)=\prod_{j=1}^{k}\frac{1-q^{m+j}}{1-q^j},\qquad k=\min(a,b),\quad m=\max(a,b).$$

This is the Gaussian \(q\)-binomial coefficient associated with an \(a\times b\) rectangle. The final target is

$$S=\sum_{r=1}^{7} C(10^r+r,10^r+r,r)\pmod{10^9+7}.$$

The challenge is therefore to evaluate seven very large Gaussian coefficients modulo a prime, not to enumerate individual paths.

Mathematical Approach

The C++, Python, and Java implementations all use the same algebraic strategy: evaluate the Gaussian product directly, treat the singular case \(q=1\) separately, and accumulate the seven required terms modulo \(10^9+7\).

Step 1: Express the weighted path count as a finite product

The problem uses the standard Gaussian \(q\)-binomial coefficient

$$C(a,b,q)=\prod_{j=1}^{k}\frac{1-q^{m+j}}{1-q^j},\qquad k=\min(a,b),\quad m=\max(a,b).$$

Because \(k+m=a+b\), this is the \(q\)-analogue of an ordinary binomial coefficient. Writing the formula with \(k=\min(a,b)\) is important computationally, because it keeps the product length as small as possible.

Step 2: Interpret it as a weighted lattice-path generating function

The same quantity can be viewed combinatorially as

$$C(a,b,q)=\sum_{P} q^{A(P)},$$

where the sum runs over monotone lattice paths from \((0,0)\) to \((a,b)\), and \(A(P)\) is a standard area or inversion statistic attached to the path. This interpretation explains why the answer is a polynomial in \(q\) with nonnegative coefficients, while the product form gives the fast evaluation method used in the implementations.

Symmetry of the rectangle also explains why exchanging \(a\) and \(b\) does not change the value, so reducing to \(k=\min(a,b)\) loses no information.

Step 3: Handle the special case \(q=1\)

The product has denominator factors \(1-q^j\), so the case \(q=1\) cannot be plugged in directly. Instead we take the limit term by term:

$$\lim_{q\to 1}\frac{1-q^{m+j}}{1-q^j}=\frac{m+j}{j}.$$

Multiplying these limits gives

$$C(a,b,1)=\prod_{j=1}^{k}\frac{m+j}{j}=\binom{a+b}{a}=\binom{a+b}{b}.$$

For the required sum, \(q=1\) appears only in the first term, where \(a=b=11\). That is why the implementation can evaluate this branch with a tiny precomputed factorial table.

Step 4: Evaluate the product modulo the prime \(10^9+7\)

For \(q>1\), the implementations split the product into a numerator and a denominator:

$$N=\prod_{j=1}^{k}(1-q^{m+j}),\qquad D=\prod_{j=1}^{k}(1-q^j).$$

Then

$$C(a,b,q)\equiv N\cdot D^{-1}\pmod M,\qquad M=10^9+7.$$

Since \(M\) is prime, the inverse is computed with Fermat's little theorem:

$$D^{-1}\equiv D^{M-2}\pmod M.$$

The loop is organized to avoid repeated exponentiation inside the product. It computes \(q^m\) once, updates \(q^j\) incrementally, and obtains \(q^{m+j}\) from the product \(q^m\cdot q^j\pmod M\).

Step 5: Apply the formula to Problem 638

Define

$$n_r=10^r+r\qquad (1\le r\le 7).$$

Because the problem uses equal side lengths, each summand is

$$C(n_r,n_r,r)=\prod_{j=1}^{n_r}\frac{1-r^{n_r+j}}{1-r^j}\pmod{10^9+7}.$$

Therefore the final answer is

$$\boxed{S=\sum_{r=1}^{7} C(n_r,n_r,r)\pmod{10^9+7}.}$$

The only qualitative difference between the seven terms is that the first one uses the ordinary binomial shortcut, while the other six use the modular product.

Worked Example: \(C(2,2,2)\)

Here \(k=m=2\), so the product becomes

$$C(2,2,2)=\frac{(1-2^3)(1-2^4)}{(1-2)(1-2^2)}=\frac{(-7)(-15)}{(-1)(-3)}=35.$$

The same value can be read from the polynomial form

$$C(2,2,q)=1+q+2q^2+q^3+q^4.$$

Substituting \(q=2\) gives \(35\), while substituting \(q=1\) gives \(6\). These are useful sanity checks because they confirm both the weighted version and the ordinary binomial limit.

How the Code Works

The C++, Python, and Java implementations begin with simple boundary cases. Negative dimensions are rejected, and if either side length is zero the answer is \(1\), because there is exactly one monotone path along the border of the rectangle.

Next they branch on \(q\). For \(q=1\), they evaluate the ordinary binomial coefficient modulo \(10^9+7\) using precomputed factorials and inverse factorials. In this problem that table can stay very small, because the only \(q=1\) contribution is \(C(11,11,1)\).

For \(q>1\), the implementation chooses the smaller of \(a\) and \(b\) as the loop length, computes one initial modular power \(q^m\), then walks through \(j=1,\dots,k\). During that loop it multiplies one accumulator by \(1-q^j\) and the other by \(1-q^{m+j}\), reducing modulo \(10^9+7\) after every step.

Once the loop is finished, the numerator is multiplied by the modular inverse of the denominator. The top-level routine then evaluates the seven required values \(C(10^r+r,10^r+r,r)\) for \(r=1,\dots,7\) and adds them modulo \(10^9+7\).

Complexity Analysis

One evaluation of \(C(a,b,q)\) with \(q>1\) takes \(O(\min(a,b)+\log \max(a,b))\) time. The logarithmic term comes from modular exponentiation, and the linear term comes from the product loop. Extra memory is \(O(1)\), apart from the fixed tiny table used for the \(q=1\) branch.

For Problem 638, the dominant work is the sum of the seven loop lengths:

$$\sum_{r=1}^{7}(10^r+r)=11{,}111{,}138.$$

So the overall running time is effectively linear in about eleven million modular multiplication steps, which is easily practical in all three languages.

Footnotes and References

  1. Problem page: https://projecteuler.net/problem=638
  2. Gaussian binomial coefficient: Wikipedia - Gaussian binomial coefficient
  3. Lattice path: Wikipedia - Lattice path
  4. Modular multiplicative inverse: Wikipedia - Modular multiplicative inverse
  5. Fermat's little theorem: Wikipedia - Fermat's little theorem

Problemzusammenfassung

Problem 638 verlangt eine Summe gewichteter monotone Gitterpfade. Für nichtnegative ganze Zahlen \(a\) und \(b\) ist die zentrale Größe

$$C(a,b,q)=\prod_{j=1}^{k}\frac{1-q^{m+j}}{1-q^j},\qquad k=\min(a,b),\quad m=\max(a,b).$$

Das ist der gaussische \(q\)-Binomialkoeffizient eines \(a\times b\)-Rechtecks. Gesucht ist am Ende

$$S=\sum_{r=1}^{7} C(10^r+r,10^r+r,r)\pmod{10^9+7}.$$

Man zählt die Pfade also nicht direkt, sondern wertet sieben sehr große \(q\)-Binomialkoeffizienten modulo einer Primzahl aus.

Mathematischer Ansatz

Die C++-, Python- und Java-Implementierungen folgen derselben Idee: die Produktform direkt auswerten, den singulären Fall \(q=1\) separat behandeln und alle sieben Summanden modulo \(10^9+7\) aufsummieren.

Schritt 1: Die gewichtete Pfadzahl als endliches Produkt schreiben

Verwendet wird der Standardausdruck für den gaussischen \(q\)-Binomialkoeffizienten

$$C(a,b,q)=\prod_{j=1}^{k}\frac{1-q^{m+j}}{1-q^j},\qquad k=\min(a,b),\quad m=\max(a,b).$$

Da \(k+m=a+b\) gilt, ist dies das \(q\)-Analogon eines gewöhnlichen Binomialkoeffizienten. Die Schreibweise mit \(k=\min(a,b)\) ist rechnerisch wichtig, weil sie die Zahl der Faktoren minimiert.

Schritt 2: Interpretation als gewichtende Gitterpfad-Erzeugende

Dieselbe Größe lässt sich auch kombinatorisch auffassen als

$$C(a,b,q)=\sum_{P} q^{A(P)},$$

wobei über monotone Gitterpfade von \((0,0)\) nach \((a,b)\) summiert wird und \(A(P)\) eine übliche Flächen- oder Inversionsstatistik des Pfades bezeichnet. Dadurch ist klar, warum das Ergebnis ein Polynom in \(q\) mit nichtnegativen Koeffizienten ist, während die Produktform die schnelle Auswertung liefert.

Die Symmetrie des Rechtecks erklärt zugleich, warum der Tausch von \(a\) und \(b\) den Wert nicht ändert. Daher darf die Implementierung immer mit dem kleineren der beiden Parameter iterieren.

Schritt 3: Der Sonderfall \(q=1\)

In der Produktform treten Nenner \(1-q^j\) auf; für \(q=1\) kann man deshalb nicht direkt einsetzen. Stattdessen nimmt man den Grenzwert jedes Faktors:

$$\lim_{q\to 1}\frac{1-q^{m+j}}{1-q^j}=\frac{m+j}{j}.$$

Durch Multiplikation folgt

$$C(a,b,1)=\prod_{j=1}^{k}\frac{m+j}{j}=\binom{a+b}{a}=\binom{a+b}{b}.$$

In der Zielsumme tritt \(q=1\) nur im ersten Summanden auf, also bei \(a=b=11\). Deshalb reicht für diesen Zweig eine sehr kleine vorab berechnete Fakultätentabelle.

Schritt 4: Auswertung modulo der Primzahl \(10^9+7\)

Für \(q>1\) zerlegen die Implementierungen das Produkt in Zähler und Nenner:

$$N=\prod_{j=1}^{k}(1-q^{m+j}),\qquad D=\prod_{j=1}^{k}(1-q^j).$$

Dann gilt

$$C(a,b,q)\equiv N\cdot D^{-1}\pmod M,\qquad M=10^9+7.$$

Weil \(M\) prim ist, wird die Inverse mit dem kleinen Satz von Fermat berechnet:

$$D^{-1}\equiv D^{M-2}\pmod M.$$

Um unnötige Potenzierungen zu vermeiden, wird \(q^m\) einmal berechnet, \(q^j\) im Loop fortlaufend aktualisiert und \(q^{m+j}\) als \(q^m\cdot q^j\pmod M\) gewonnen.

Schritt 5: Anwendung auf Problem 638

Setze

$$n_r=10^r+r\qquad (1\le r\le 7).$$

Da im Problem beide Seitenlängen gleich sind, hat jeder Summand die Form

$$C(n_r,n_r,r)=\prod_{j=1}^{n_r}\frac{1-r^{n_r+j}}{1-r^j}\pmod{10^9+7}.$$

Damit lautet die Endformel

$$\boxed{S=\sum_{r=1}^{7} C(n_r,n_r,r)\pmod{10^9+7}.}$$

Der einzige qualitative Unterschied zwischen den sieben Summanden besteht darin, dass der erste den gewöhnlichen Binomialfall nutzt und die restlichen sechs das modulare Produkt.

Durchgerechnetes Beispiel: \(C(2,2,2)\)

Hier ist \(k=m=2\), also

$$C(2,2,2)=\frac{(1-2^3)(1-2^4)}{(1-2)(1-2^2)}=\frac{(-7)(-15)}{(-1)(-3)}=35.$$

Dasselbe Ergebnis erhält man aus der Polynomform

$$C(2,2,q)=1+q+2q^2+q^3+q^4.$$

Für \(q=2\) ergibt sich \(35\), für \(q=1\) ergibt sich \(6\). Diese beiden kleinen Werte sind nützliche Plausibilitätskontrollen für Produktform und Grenzfall.

Wie der Code arbeitet

Die C++-, Python- und Java-Implementierungen beginnen mit einfachen Randfällen. Negative Dimensionen liefern \(0\), und wenn eine Seite des Rechtecks null ist, gibt es genau einen monotonen Randpfad, also den Wert \(1\).

Danach wird nach \(q\) verzweigt. Für \(q=1\) wird der gewöhnliche Binomialkoeffizient modulo \(10^9+7\) mit vorab berechneten Fakultäten und inversen Fakultäten bestimmt. Für dieses Problem bleibt diese Tabelle klein, weil nur \(C(11,11,1)\) in diesen Zweig fällt.

Für \(q>1\) wählt die Implementierung die kleinere der beiden Dimensionen als Schleifenlänge, berechnet einmal \(q^m\) und läuft dann durch \(j=1,\dots,k\). In jedem Schritt wird ein Akkumulator mit \(1-q^j\) und der andere mit \(1-q^{m+j}\) multipliziert, jeweils modulo \(10^9+7\).

Nach der Schleife wird der Zähler mit der modularen Inversen des Nenners multipliziert. Die Hauptroutine berechnet danach die sieben Werte \(C(10^r+r,10^r+r,r)\) für \(r=1,\dots,7\) und summiert sie modulo \(10^9+7\).

Komplexitätsanalyse

Eine Auswertung von \(C(a,b,q)\) mit \(q>1\) benötigt \(O(\min(a,b)+\log \max(a,b))\) Zeit. Der logarithmische Anteil stammt aus der modularen Potenzierung, der lineare Anteil aus der Produktschleife. Der Zusatzspeicher ist \(O(1)\), abgesehen von der festen kleinen Tabelle für den Fall \(q=1\).

Für Problem 638 dominiert die Summe der sieben Schleifenlängen:

$$\sum_{r=1}^{7}(10^r+r)=11{,}111{,}138.$$

Die Gesamtlaufzeit ist damit praktisch linear in rund elf Millionen modularen Multiplikationsschritten und in allen drei Sprachen gut beherrschbar.

Fußnoten und Quellen

  1. Problemseite: https://projecteuler.net/problem=638
  2. Gaussischer Binomialkoeffizient: Wikipedia - Gaussian binomial coefficient
  3. Gitterpfad: Wikipedia - Lattice path
  4. Modulares multiplikatives Inverses: Wikipedia - Modular multiplicative inverse
  5. Kleiner Satz von Fermat: Wikipedia - Fermat's little theorem

Problem Özeti

Problem 638, ağırlıklı monoton kafes-yolu sayılarının toplamını ister. Negatif olmayan \(a\) ve \(b\) için temel nicelik

$$C(a,b,q)=\prod_{j=1}^{k}\frac{1-q^{m+j}}{1-q^j},\qquad k=\min(a,b),\quad m=\max(a,b).$$

Bu ifade, \(a\times b\) dikdörtgenine karşılık gelen Gaussian \(q\)-binom katsayısıdır. İstenen son toplam

$$S=\sum_{r=1}^{7} C(10^r+r,10^r+r,r)\pmod{10^9+7}.$$

Dolayısıyla amaç, yolları tek tek üretmek değil; bu yedi büyük Gaussian katsayıyı asal bir mod altında verimli biçimde hesaplamaktır.

Matematiksel Yaklaşım

C++, Python ve Java uygulamalarının ortak yaklaşımı aynıdır: Gaussian çarpım formunu doğrudan kullanmak, \(q=1\) durumunu ayrı ele almak ve yedi terimi \(10^9+7\) modunda toplamak.

Adım 1: Ağırlıklı yol sayısını sonlu bir çarpım olarak yaz

Kullanılan standart formül şudur:

$$C(a,b,q)=\prod_{j=1}^{k}\frac{1-q^{m+j}}{1-q^j},\qquad k=\min(a,b),\quad m=\max(a,b).$$

\(k+m=a+b\) olduğundan bu ifade sıradan binom katsayısının \(q\)-analogudur. Hesaplama açısından \(k=\min(a,b)\) seçimi kritiktir; çünkü döngü uzunluğunu en küçük tarafa indirir.

Adım 2: Bunu ağırlıklı kafes-yolu üreteci olarak yorumla

Aynı nicelik kombinatorik olarak

$$C(a,b,q)=\sum_{P} q^{A(P)}$$

şeklinde de görülebilir. Burada toplam, \((0,0)\)'dan \((a,b)\)'ye giden monoton kafes yolları üzerinde alınır; \(A(P)\) ise yolun alan ya da terslik sayımı türünden standart bir istatistiğidir. Bu yorum, sonucun neden negatif olmayan katsayılara sahip bir \(q\)-polinomu olduğunu açıklar; çarpım formu ise hızlı sayısal değerlendirme yolunu verir.

Dikdörtgenin simetrisi yüzünden \(a\) ile \(b\)'yi yer değiştirmek değeri değiştirmez. Bu yüzden uygulama güvenle küçük olan boyut üzerinden ilerler.

Adım 3: \(q=1\) özel durumunu ayrı çöz

Çarpımın paydasında \(1-q^j\) terimleri vardır; bu nedenle \(q=1\) doğrudan yerine konulamaz. Bunun yerine her çarpan için limit alınır:

$$\lim_{q\to 1}\frac{1-q^{m+j}}{1-q^j}=\frac{m+j}{j}.$$

Hepsi çarpılınca

$$C(a,b,1)=\prod_{j=1}^{k}\frac{m+j}{j}=\binom{a+b}{a}=\binom{a+b}{b}$$

elde edilir. Gerekli toplamda \(q=1\) yalnızca ilk terimde ortaya çıkar; orada \(a=b=11\) olduğundan küçük bir faktöriyel tablosu yeterlidir.

Adım 4: Çarpımı asal mod \(10^9+7\) altında hesapla

\(q>1\) için uygulamalar çarpımı pay ve payda olarak ayırır:

$$N=\prod_{j=1}^{k}(1-q^{m+j}),\qquad D=\prod_{j=1}^{k}(1-q^j).$$

Böylece

$$C(a,b,q)\equiv N\cdot D^{-1}\pmod M,\qquad M=10^9+7$$

olur. \(M\) asal olduğu için ters alma işlemi Fermat'nın küçük teoremiyle yapılır:

$$D^{-1}\equiv D^{M-2}\pmod M.$$

İç döngüde gereksiz üs alma yapılmaz. Önce \(q^m\) bir kez hesaplanır, sonra \(q^j\) artımlı biçimde güncellenir ve \(q^{m+j}\) değeri \(q^m\cdot q^j\pmod M\) olarak elde edilir.

Adım 5: Formülü Problem 638'e uygula

Şu tanımı yapalım:

$$n_r=10^r+r\qquad (1\le r\le 7).$$

Problemde iki kenar eşit olduğundan her terim

$$C(n_r,n_r,r)=\prod_{j=1}^{n_r}\frac{1-r^{n_r+j}}{1-r^j}\pmod{10^9+7}$$

şeklindedir. Sonuç olarak aranan değer

$$\boxed{S=\sum_{r=1}^{7} C(n_r,n_r,r)\pmod{10^9+7}.}$$

Yedi terim arasındaki tek nitel fark, ilk terimin sıradan binom kısa yolunu kullanması, diğer altı terimin ise modüler çarpımla hesaplanmasıdır.

Çözümlü Örnek: \(C(2,2,2)\)

Burada \(k=m=2\) olur ve

$$C(2,2,2)=\frac{(1-2^3)(1-2^4)}{(1-2)(1-2^2)}=\frac{(-7)(-15)}{(-1)(-3)}=35$$

hesabı çıkar. Aynı değer polinom biçiminden de okunur:

$$C(2,2,q)=1+q+2q^2+q^3+q^4.$$

\(q=2\) için sonuç \(35\), \(q=1\) için ise \(6\) olur. Bu iki küçük değer, hem ağırlıklı sürümü hem de binom limitini doğrulayan kullanışlı kontrollerdir.

Kod Nasıl Çalışır

C++, Python ve Java uygulamaları önce basit sınır durumlarını ele alır. Negatif boyutlarda sonuç \(0\) kabul edilir; kenarlardan biri sıfırsa sınır boyunca yalnızca bir monoton yol bulunduğu için sonuç \(1\) olur.

Daha sonra \(q\)'ya göre iki kola ayrılır. \(q=1\) için sıradan binom katsayısı, \(10^9+7\) modunda önceden hazırlanmış faktöriyel ve ters faktöriyel tablolarıyla hesaplanır. Bu problemde bu tablo çok küçük kalabilir; çünkü bu kola düşen tek katkı \(C(11,11,1)\)'dir.

\(q>1\) olduğunda uygulama döngü uzunluğu olarak \(a\) ve \(b\)'nin küçüğünü seçer, bir kez \(q^m\) hesaplar ve ardından \(j=1,\dots,k\) üzerinden ilerler. Döngü sırasında bir çarpan biriktiricisi \(1-q^j\) ile, diğeri \(1-q^{m+j}\) ile sürekli güncellenir; her adımda mod alınır.

Döngü bittiğinde pay, paydanın modüler tersiyle çarpılır. En üst düzeyde de \(r=1,\dots,7\) için gereken yedi değer hesaplanıp \(10^9+7\) modunda toplanır.

Karmaşıklık Analizi

\(q>1\) için tek bir \(C(a,b,q)\) hesabı \(O(\min(a,b)+\log \max(a,b))\) zamanda tamamlanır. Logaritmik kısım modüler üs almadan, doğrusal kısım ise çarpım döngüsünden gelir. \(q=1\) kolundaki sabit küçük tablo dışında ek bellek maliyeti \(O(1)\)'dir.

Problem 638 için baskın iş yükü yedi döngü uzunluğunun toplamıdır:

$$\sum_{r=1}^{7}(10^r+r)=11{,}111{,}138.$$

Bu nedenle toplam çalışma süresi, yaklaşık on bir milyon modüler çarpma adımında doğrusal davranır ve üç dilde de rahatlıkla uygulanabilir.

Dipnotlar ve Kaynaklar

  1. Problem sayfası: https://projecteuler.net/problem=638
  2. Gaussian binom katsayısı: Wikipedia - Gaussian binomial coefficient
  3. Kafes yolu: Wikipedia - Lattice path
  4. Modüler çarpımsal ters: Wikipedia - Modular multiplicative inverse
  5. Fermat'nın küçük teoremi: Wikipedia - Fermat's little theorem

Resumen del Problema

El problema 638 pide una suma de conteos ponderados de caminos monótonos en una retícula. Para enteros no negativos \(a\) y \(b\), la cantidad central es

$$C(a,b,q)=\prod_{j=1}^{k}\frac{1-q^{m+j}}{1-q^j},\qquad k=\min(a,b),\quad m=\max(a,b).$$

Este es el coeficiente binomial gaussiano asociado a un rectángulo \(a\times b\). El objetivo final es

$$S=\sum_{r=1}^{7} C(10^r+r,10^r+r,r)\pmod{10^9+7}.$$

Por lo tanto, la tarea no consiste en enumerar caminos individualmente, sino en evaluar siete coeficientes gaussianos muy grandes módulo un primo.

Enfoque Matemático

Las implementaciones en C++, Python y Java siguen exactamente la misma idea algebraica: evaluar la forma producto, separar el caso singular \(q=1\) y acumular los siete términos módulo \(10^9+7\).

Paso 1: Escribir el conteo ponderado como un producto finito

La fórmula usada es la forma estándar del coeficiente binomial gaussiano:

$$C(a,b,q)=\prod_{j=1}^{k}\frac{1-q^{m+j}}{1-q^j},\qquad k=\min(a,b),\quad m=\max(a,b).$$

Como \(k+m=a+b\), esta expresión es el análogo en \(q\) del coeficiente binomial ordinario. Es importante usar \(k=\min(a,b)\) porque así la longitud del producto es la menor posible.

Paso 2: Interpretarlo como una función generadora de caminos ponderados

La misma cantidad también admite la interpretación combinatoria

$$C(a,b,q)=\sum_{P} q^{A(P)},$$

donde la suma recorre los caminos monótonos desde \((0,0)\) hasta \((a,b)\) y \(A(P)\) es una estadística estándar de área o de inversiones del camino. Esto explica por qué el resultado es un polinomio en \(q\) con coeficientes no negativos, mientras que la forma producto proporciona el método eficiente de evaluación.

La simetría del rectángulo muestra además que intercambiar \(a\) y \(b\) no cambia el valor. Por eso es natural iterar solo hasta la dimensión menor.

Paso 3: Resolver por separado el caso \(q=1\)

La forma producto contiene denominadores \(1-q^j\), de modo que no se puede sustituir \(q=1\) directamente. Se toma el límite factor por factor:

$$\lim_{q\to 1}\frac{1-q^{m+j}}{1-q^j}=\frac{m+j}{j}.$$

Al multiplicar estos límites se obtiene

$$C(a,b,1)=\prod_{j=1}^{k}\frac{m+j}{j}=\binom{a+b}{a}=\binom{a+b}{b}.$$

En la suma pedida, \(q=1\) aparece solo en el primer término, donde \(a=b=11\). Por eso basta una tabla muy pequeña de factoriales precalculados.

Paso 4: Evaluar el producto módulo el primo \(10^9+7\)

Cuando \(q>1\), las implementaciones separan numerador y denominador:

$$N=\prod_{j=1}^{k}(1-q^{m+j}),\qquad D=\prod_{j=1}^{k}(1-q^j).$$

Entonces

$$C(a,b,q)\equiv N\cdot D^{-1}\pmod M,\qquad M=10^9+7.$$

Como \(M\) es primo, la inversa se calcula con el pequeño teorema de Fermat:

$$D^{-1}\equiv D^{M-2}\pmod M.$$

La implementación evita exponentiaciones repetidas dentro del bucle. Calcula \(q^m\) una sola vez, actualiza \(q^j\) de forma incremental y obtiene \(q^{m+j}\) como \(q^m\cdot q^j\pmod M\).

Paso 5: Aplicar la fórmula al Problema 638

Definimos

$$n_r=10^r+r\qquad (1\le r\le 7).$$

Como en el problema ambos lados del rectángulo son iguales, cada sumando queda

$$C(n_r,n_r,r)=\prod_{j=1}^{n_r}\frac{1-r^{n_r+j}}{1-r^j}\pmod{10^9+7}.$$

Por lo tanto, la respuesta final es

$$\boxed{S=\sum_{r=1}^{7} C(n_r,n_r,r)\pmod{10^9+7}.}$$

La única diferencia cualitativa entre los siete términos es que el primero usa el atajo binomial ordinario y los otros seis usan el producto modular.

Ejemplo resuelto: \(C(2,2,2)\)

Aquí \(k=m=2\), de modo que

$$C(2,2,2)=\frac{(1-2^3)(1-2^4)}{(1-2)(1-2^2)}=\frac{(-7)(-15)}{(-1)(-3)}=35.$$

El mismo valor aparece en la forma polinómica

$$C(2,2,q)=1+q+2q^2+q^3+q^4.$$

Al sustituir \(q=2\) se obtiene \(35\), y al sustituir \(q=1\) se obtiene \(6\). Esas dos cifras son verificaciones pequeñas y útiles del método.

Cómo Funciona el Código

Las implementaciones en C++, Python y Java empiezan con casos frontera sencillos. Si las dimensiones son negativas, devuelven \(0\); si uno de los lados es cero, devuelven \(1\), porque solo existe un camino monótono por el borde.

Después separan el tratamiento según \(q\). Cuando \(q=1\), evalúan el coeficiente binomial ordinario módulo \(10^9+7\) con factoriales e inversos factoriales precalculados. En este problema esa tabla puede ser muy pequeña, porque la única contribución con \(q=1\) es \(C(11,11,1)\).

Cuando \(q>1\), la implementación toma la menor de las dos dimensiones como longitud del bucle, calcula una vez \(q^m\) y luego recorre \(j=1,\dots,k\). Durante ese recorrido actualiza un acumulador con \(1-q^j\) y otro con \(1-q^{m+j}\), reduciendo módulo \(10^9+7\) en cada paso.

Al finalizar, multiplica el numerador acumulado por la inversa modular del denominador acumulado. La rutina principal evalúa después los siete valores \(C(10^r+r,10^r+r,r)\) para \(r=1,\dots,7\) y los suma módulo \(10^9+7\).

Análisis de Complejidad

Una evaluación de \(C(a,b,q)\) con \(q>1\) cuesta \(O(\min(a,b)+\log \max(a,b))\) tiempo. La parte logarítmica proviene de la exponenciación modular y la parte lineal del bucle del producto. La memoria extra es \(O(1)\), salvo la tabla fija y muy pequeña usada en el caso \(q=1\).

Para el Problema 638, el trabajo dominante es la suma de las siete longitudes de bucle:

$$\sum_{r=1}^{7}(10^r+r)=11{,}111{,}138.$$

En consecuencia, el tiempo total es esencialmente lineal en unos once millones de multiplicaciones modulares, algo perfectamente razonable en los tres lenguajes.

Notas y Referencias

  1. Página del problema: https://projecteuler.net/problem=638
  2. Coeficiente binomial gaussiano: Wikipedia - Gaussian binomial coefficient
  3. Camino en retícula: Wikipedia - Lattice path
  4. Inverso multiplicativo modular: Wikipedia - Modular multiplicative inverse
  5. Pequeño teorema de Fermat: Wikipedia - Fermat's little theorem

问题概述

第 638 题要求的是一组带权单调格路径计数的总和。对非负整数 \(a\) 和 \(b\),核心量定义为

$$C(a,b,q)=\prod_{j=1}^{k}\frac{1-q^{m+j}}{1-q^j},\qquad k=\min(a,b),\quad m=\max(a,b).$$

它就是与 \(a\times b\) 矩形对应的 Gaussian \(q\)-二项式系数。题目真正要求的是

$$S=\sum_{r=1}^{7} C(10^r+r,10^r+r,r)\pmod{10^9+7}.$$

因此难点不在于逐条枚举路径,而在于如何把这七个非常大的 Gaussian 系数在素数模数下稳定而高效地求出来。

数学方法

C++、Python 和 Java 实现采用的是同一套数学思路:直接计算 Gaussian 乘积公式,对 \(q=1\) 的奇异情形单独处理,然后把七项结果在 \(10^9+7\) 下相加。

步骤 1:把带权路径计数写成有限乘积

使用的标准闭式是

$$C(a,b,q)=\prod_{j=1}^{k}\frac{1-q^{m+j}}{1-q^j},\qquad k=\min(a,b),\quad m=\max(a,b).$$

由于 \(k+m=a+b\),这个表达式正是普通二项式系数的 \(q\)-模拟。把公式写成 \(k=\min(a,b)\) 的形式还有直接的计算意义,因为这样只需要进行较短的一侧长度那么多次乘法。

步骤 2:把它看成带权格路径的生成函数

同一个量也可以从组合意义上写成

$$C(a,b,q)=\sum_{P} q^{A(P)},$$

其中求和对象是从 \((0,0)\) 到 \((a,b)\) 的所有单调格路径,\(A(P)\) 是路径对应的标准面积统计或逆序统计。这个解释说明了为什么结果一定是一个系数非负的 \(q\)-多项式,而乘积公式则提供了实际实现时更快的数值求法。

矩形在交换两条边后保持同类,因此 \(a\) 和 \(b\) 互换不会改变值。实现只对较小的一边做循环,正是利用了这种对称性。

步骤 3:单独处理 \(q=1\) 的极限情形

原公式的分母里有 \(1-q^j\),所以不能把 \(q=1\) 直接代入。正确做法是逐项取极限:

$$\lim_{q\to 1}\frac{1-q^{m+j}}{1-q^j}=\frac{m+j}{j}.$$

把这些极限连乘起来,就得到

$$C(a,b,1)=\prod_{j=1}^{k}\frac{m+j}{j}=\binom{a+b}{a}=\binom{a+b}{b}.$$

在本题要求的七项总和里,只有第一项对应 \(q=1\),而那时 \(a=b=11\)。这就是为什么实现只需要一张很小的阶乘表就能处理这一分支。

步骤 4:在素数模 \(10^9+7\) 下计算乘积

当 \(q>1\) 时,实现把原式拆成分子与分母:

$$N=\prod_{j=1}^{k}(1-q^{m+j}),\qquad D=\prod_{j=1}^{k}(1-q^j).$$

于是

$$C(a,b,q)\equiv N\cdot D^{-1}\pmod M,\qquad M=10^9+7.$$

因为 \(M\) 是素数,所以可以用费马小定理求逆:

$$D^{-1}\equiv D^{M-2}\pmod M.$$

实现中不会在循环内反复做昂贵的幂运算。它先算出一次 \(q^m\),再迭代维护 \(q^j\),而 \(q^{m+j}\) 则由 \(q^m\cdot q^j\pmod M\) 直接得到。

步骤 5:把公式代入本题要求的七项和

$$n_r=10^r+r\qquad (1\le r\le 7).$$

由于题目中的两个参数相等,所以每一项都是

$$C(n_r,n_r,r)=\prod_{j=1}^{n_r}\frac{1-r^{n_r+j}}{1-r^j}\pmod{10^9+7}.$$

因此最终答案就是

$$\boxed{S=\sum_{r=1}^{7} C(n_r,n_r,r)\pmod{10^9+7}.}$$

七项之间唯一的结构差别在于第一项走普通二项式分支,其余六项走模意义下的乘积分支。

例子:\(C(2,2,2)\)

此时 \(k=m=2\),所以

$$C(2,2,2)=\frac{(1-2^3)(1-2^4)}{(1-2)(1-2^2)}=\frac{(-7)(-15)}{(-1)(-3)}=35.$$

同一个结果也可以从多项式形式直接看出来:

$$C(2,2,q)=1+q+2q^2+q^3+q^4.$$

代入 \(q=2\) 得到 \(35\),代入 \(q=1\) 得到 \(6\)。这两个小例子很适合用来同时检查带权版本和 \(q\to1\) 的极限版本是否一致。

代码如何工作

C++、Python 和 Java 实现首先处理一些简单边界情况。若维度为负,则返回 \(0\);若某一条边为零,则只存在一条沿边界前进的单调路径,因此返回 \(1\)。

接下来根据 \(q\) 的取值分成两条路径。若 \(q=1\),实现就用预先准备好的阶乘和逆阶乘表来计算普通二项式系数,并在 \(10^9+7\) 下取模。由于本题里只有 \(C(11,11,1)\) 落到这一分支,所以这张表可以非常小。

若 \(q>1\),实现会先取 \(a\) 与 \(b\) 中较小者作为循环长度,再计算一次 \(q^m\),然后按 \(j=1,\dots,k\) 顺序推进。循环中一个累乘器不断乘上 \(1-q^j\),另一个累乘器不断乘上 \(1-q^{m+j}\),每一步都立即模 \(10^9+7\)。

循环结束后,再用分母累乘器的模逆去乘分子累乘器,得到当前的 Gaussian 系数。最外层过程随后计算七个值 \(C(10^r+r,10^r+r,r)\),并把它们逐项加总到最终答案中。

复杂度分析

对 \(q>1\) 的一次 \(C(a,b,q)\) 计算,时间复杂度是 \(O(\min(a,b)+\log \max(a,b))\)。其中对数项来自模幂运算,线性项来自乘积循环。额外空间复杂度是 \(O(1)\),只有 \(q=1\) 分支使用了一张固定且很小的常量级表。

对第 638 题来说,主导成本就是七次循环长度之和:

$$\sum_{r=1}^{7}(10^r+r)=11{,}111{,}138.$$

因此总运行时间本质上就是大约一千一百一十一万次模乘的线性规模,在这三种语言里都完全可行。

注释与参考资料

  1. 题目页面:https://projecteuler.net/problem=638
  2. Gaussian \(q\)-二项式系数:Wikipedia - Gaussian binomial coefficient
  3. 格路径:Wikipedia - Lattice path
  4. 模乘法逆元:Wikipedia - Modular multiplicative inverse
  5. 费马小定理:Wikipedia - Fermat's little theorem

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

Задача 638 просит найти сумму взвешенных количеств монотонных путей на решетке. Для неотрицательных целых \(a\) и \(b\) основная величина равна

$$C(a,b,q)=\prod_{j=1}^{k}\frac{1-q^{m+j}}{1-q^j},\qquad k=\min(a,b),\quad m=\max(a,b).$$

Это гауссов \(q\)-биномиальный коэффициент для прямоугольника \(a\times b\). Требуется вычислить

$$S=\sum_{r=1}^{7} C(10^r+r,10^r+r,r)\pmod{10^9+7}.$$

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

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

Реализации на C++, Python и Java используют одну и ту же схему: напрямую вычисляют гауссово произведение, отдельно обрабатывают особый случай \(q=1\) и суммируют семь нужных членов по модулю \(10^9+7\).

Шаг 1: Записать взвешенное число путей в виде конечного произведения

Используется стандартная формула

$$C(a,b,q)=\prod_{j=1}^{k}\frac{1-q^{m+j}}{1-q^j},\qquad k=\min(a,b),\quad m=\max(a,b).$$

Так как \(k+m=a+b\), это \(q\)-аналог обычного биномиального коэффициента. Выбор \(k=\min(a,b)\) важен вычислительно: длина цикла становится минимально возможной.

Шаг 2: Понять его как производящую функцию взвешенных путей

Ту же величину можно интерпретировать комбинаторно:

$$C(a,b,q)=\sum_{P} q^{A(P)},$$

где суммирование ведется по всем монотонным путям из \((0,0)\) в \((a,b)\), а \(A(P)\) обозначает стандартную статистику площади или инверсий, связанную с путем. Именно поэтому ответ является многочленом по \(q\) с неотрицательными коэффициентами, тогда как произведение дает удобный способ численного вычисления.

Симметрия прямоугольника также показывает, что перестановка \(a\) и \(b\) не меняет значение. Поэтому достаточно итерироваться только по меньшей стороне.

Шаг 3: Отдельно обработать случай \(q=1\)

В произведении стоят знаменатели \(1-q^j\), поэтому подставлять \(q=1\) напрямую нельзя. Нужно взять предел каждого множителя:

$$\lim_{q\to 1}\frac{1-q^{m+j}}{1-q^j}=\frac{m+j}{j}.$$

После перемножения получаем

$$C(a,b,1)=\prod_{j=1}^{k}\frac{m+j}{j}=\binom{a+b}{a}=\binom{a+b}{b}.$$

В требуемой сумме случай \(q=1\) возникает только для первого слагаемого, где \(a=b=11\). Поэтому для этой ветви достаточно совсем небольшой таблицы факториалов.

Шаг 4: Вычислить произведение по модулю простого числа \(10^9+7\)

При \(q>1\) реализации разделяют формулу на числитель и знаменатель:

$$N=\prod_{j=1}^{k}(1-q^{m+j}),\qquad D=\prod_{j=1}^{k}(1-q^j).$$

Тогда

$$C(a,b,q)\equiv N\cdot D^{-1}\pmod M,\qquad M=10^9+7.$$

Поскольку \(M\) простое, обратный элемент находится по малой теореме Ферма:

$$D^{-1}\equiv D^{M-2}\pmod M.$$

Чтобы не выполнять лишние возведения в степень внутри цикла, сначала один раз вычисляется \(q^m\), затем последовательно поддерживается \(q^j\), а величина \(q^{m+j}\) получается как \(q^m\cdot q^j\pmod M\).

Шаг 5: Применить формулу к условию задачи

Обозначим

$$n_r=10^r+r\qquad (1\le r\le 7).$$

Так как в задаче обе стороны равны, каждое слагаемое имеет вид

$$C(n_r,n_r,r)=\prod_{j=1}^{n_r}\frac{1-r^{n_r+j}}{1-r^j}\pmod{10^9+7}.$$

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

$$\boxed{S=\sum_{r=1}^{7} C(n_r,n_r,r)\pmod{10^9+7}.}$$

Единственное принципиальное отличие первого члена от остальных состоит в том, что он использует обычный биномиальный предел, а шесть следующих считаются по модульному произведению.

Разобранный пример: \(C(2,2,2)\)

Здесь \(k=m=2\), поэтому

$$C(2,2,2)=\frac{(1-2^3)(1-2^4)}{(1-2)(1-2^2)}=\frac{(-7)(-15)}{(-1)(-3)}=35.$$

То же значение видно и из многочленной формы

$$C(2,2,q)=1+q+2q^2+q^3+q^4.$$

Подстановка \(q=2\) дает \(35\), а подстановка \(q=1\) дает \(6\). Эти два маленьких значения удобно использовать как проверку и взвешенной версии, и предельного перехода.

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

Реализации на C++, Python и Java начинают с простых граничных случаев. Отрицательные размеры отвергаются, а если одна из сторон равна нулю, ответ равен \(1\), потому что существует ровно один монотонный путь вдоль границы прямоугольника.

Далее выполнение делится по значению \(q\). При \(q=1\) вычисляется обычный биномиальный коэффициент по модулю \(10^9+7\) с помощью заранее подготовленных факториалов и обратных факториалов. В этой задаче такая таблица может быть очень маленькой, потому что в эту ветвь попадает только \(C(11,11,1)\).

При \(q>1\) реализация берет меньшую из двух сторон как длину цикла, один раз вычисляет \(q^m\), а затем проходит по \(j=1,\dots,k\). На каждом шаге один накопитель умножается на \(1-q^j\), а другой на \(1-q^{m+j}\), и оба значения немедленно приводятся по модулю \(10^9+7\).

После цикла накопленный числитель умножается на модульную обратную к накопленному знаменателю. Затем верхний уровень вычисляет семь значений \(C(10^r+r,10^r+r,r)\) для \(r=1,\dots,7\) и складывает их по модулю \(10^9+7\).

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

Одно вычисление \(C(a,b,q)\) при \(q>1\) требует \(O(\min(a,b)+\log \max(a,b))\) времени. Логарифмическая часть идет на модульное возведение в степень, линейная часть на проход по произведению. Дополнительная память равна \(O(1)\), если не считать маленькой фиксированной таблицы для ветви \(q=1\).

Для задачи 638 основной вклад дает сумма длин всех семи циклов:

$$\sum_{r=1}^{7}(10^r+r)=11{,}111{,}138.$$

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

Примечания и ссылки

  1. Страница задачи: https://projecteuler.net/problem=638
  2. Гауссов \(q\)-биномиальный коэффициент: Wikipedia - Gaussian binomial coefficient
  3. Путь на решетке: Wikipedia - Lattice path
  4. Модульная мультипликативная обратная: Wikipedia - Modular multiplicative inverse
  5. Малая теорема Ферма: Wikipedia - Fermat's little theorem

ملخص المسألة

تطلب المسألة 638 حساب مجموعات لأعداد مسارات شبكية رتيبة موزونة. ولعددين غير سالبين \(a\) و\(b\)، فإن الكمية الأساسية هي

$$C(a,b,q)=\prod_{j=1}^{k}\frac{1-q^{m+j}}{1-q^j},\qquad k=\min(a,b),\quad m=\max(a,b).$$

وهذه هي المعامل الغاوسي الثنائي \(q\)-binomial الموافق لمستطيل أبعاده \(a\times b\). والهدف النهائي هو

$$S=\sum_{r=1}^{7} C(10^r+r,10^r+r,r)\pmod{10^9+7}.$$

إذن التحدي الحقيقي ليس تعداد المسارات واحدةً واحدة، بل تقييم سبعة معاملات Gaussian كبيرة جدا تحت مود أولي بكفاءة.

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

التنفيذات في C++ وPython وJava تعتمد الفكرة الجبرية نفسها: استعمال صيغة Gaussian الضربية مباشرة، ومعالجة الحالة الخاصة \(q=1\) على نحو منفصل، ثم جمع الحدود السبعة المطلوبة بترديد \(10^9+7\).

الخطوة 1: كتابة عدد المسارات الموزونة على هيئة حاصل ضرب منته

الصيغة المستعملة هي الصيغة القياسية لمعامل Gaussian:

$$C(a,b,q)=\prod_{j=1}^{k}\frac{1-q^{m+j}}{1-q^j},\qquad k=\min(a,b),\quad m=\max(a,b).$$

وبما أن \(k+m=a+b\)، فهذه الصيغة هي النظير \(q\)-ي للمعامل الثنائي العادي. كما أن اختيار \(k=\min(a,b)\) مهم حسابيا لأنه يجعل طول الحلقة مساويا للبعد الأصغر فقط.

الخطوة 2: تفسيرها بوصفها دالة مولدة لمسارات شبكية موزونة

يمكن تفسير الكمية نفسها تفسيرًا توافقيا على الصورة

$$C(a,b,q)=\sum_{P} q^{A(P)},$$

حيث يمتد الجمع على جميع المسارات الرتيبة من \((0,0)\) إلى \((a,b)\)، وتمثل \(A(P)\) إحصاءً قياسيا من نوع المساحة أو عدد الانقلابات المرتبط بذلك المسار. وهذا يوضح لماذا تكون النتيجة كثيرة حدود في \(q\) ذات معاملات غير سالبة، بينما تمنحنا الصيغة الضربية الطريقة الأسرع للتقييم العددي.

كما أن تناظر المستطيل يبين أن تبديل \(a\) و\(b\) لا يغير القيمة، ولذلك يكفي أن يدور التنفيذ حتى البعد الأصغر.

الخطوة 3: معالجة الحالة الخاصة \(q=1\)

تحتوي الصيغة الضربية على مقامات من الشكل \(1-q^j\)، لذلك لا يجوز التعويض المباشر بـ \(q=1\). وبدلا من ذلك نأخذ النهاية لكل عامل:

$$\lim_{q\to 1}\frac{1-q^{m+j}}{1-q^j}=\frac{m+j}{j}.$$

وبضرب هذه النهايات نحصل على

$$C(a,b,1)=\prod_{j=1}^{k}\frac{m+j}{j}=\binom{a+b}{a}=\binom{a+b}{b}.$$

وفي المجموع المطلوب هنا تظهر \(q=1\) في الحد الأول فقط، حيث \(a=b=11\). ولهذا يكفي جدول صغير جدا من المضروبات لهذه الحالة.

الخطوة 4: تقييم حاصل الضرب تحت المود الأولي \(10^9+7\)

عندما يكون \(q>1\)، يقسم التنفيذ الصيغة إلى بسط ومقام:

$$N=\prod_{j=1}^{k}(1-q^{m+j}),\qquad D=\prod_{j=1}^{k}(1-q^j).$$

وعندئذ

$$C(a,b,q)\equiv N\cdot D^{-1}\pmod M,\qquad M=10^9+7.$$

وبما أن \(M\) عدد أولي، فإن المقلوب المعياري يحسب بواسطة مبرهنة فيرما الصغرى:

$$D^{-1}\equiv D^{M-2}\pmod M.$$

ولتفادي تكرار عمليات رفع الأس داخل الحلقة، يحسب التنفيذ \(q^m\) مرة واحدة، ثم يحدث \(q^j\) تدريجيا، ويحصل على \(q^{m+j}\) من العلاقة \(q^m\cdot q^j\pmod M\).

الخطوة 5: تطبيق الصيغة على المسألة 638

لنعرّف

$$n_r=10^r+r\qquad (1\le r\le 7).$$

وبما أن ضلعي المستطيل متساويان في المسألة، فإن كل حد يساوي

$$C(n_r,n_r,r)=\prod_{j=1}^{n_r}\frac{1-r^{n_r+j}}{1-r^j}\pmod{10^9+7}.$$

ومن ثم تكون الصيغة النهائية

$$\boxed{S=\sum_{r=1}^{7} C(n_r,n_r,r)\pmod{10^9+7}.}$$

والفرق النوعي الوحيد بين الحدود السبعة هو أن الحد الأول يستعمل اختصار المعامل الثنائي العادي، أما الحدود الستة الباقية فتستعمل الصيغة الضربية المعيارية.

مثال محلول: \(C(2,2,2)\)

هنا \(k=m=2\)، ولذلك

$$C(2,2,2)=\frac{(1-2^3)(1-2^4)}{(1-2)(1-2^2)}=\frac{(-7)(-15)}{(-1)(-3)}=35.$$

ويمكن قراءة القيمة نفسها من الصورة كثيرة الحدود

$$C(2,2,q)=1+q+2q^2+q^3+q^4.$$

بالتعويض \(q=2\) نحصل على \(35\)، وبالتعويض \(q=1\) نحصل على \(6\). وهاتان القيمتان الصغيرتان مفيدتان للتحقق من صحة النسخة الموزونة وحد النهاية معا.

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

تبدأ التنفيذات في C++ وPython وJava بحالات حدودية بسيطة. فإذا كانت الأبعاد سالبة تعاد القيمة \(0\)، وإذا كان أحد البعدين صفرا تعاد القيمة \(1\) لأن هناك مسارا رتيبا واحدا فقط على حد المستطيل.

بعد ذلك يتفرع التنفيذ بحسب قيمة \(q\). فإذا كان \(q=1\)، يحسب المعامل الثنائي العادي بترديد \(10^9+7\) باستعمال مضروبات ومعكوسات مضروبية محضرة مسبقا. وفي هذه المسألة تبقى هذه الجداول صغيرة جدا، لأن الحد الوحيد في هذا الفرع هو \(C(11,11,1)\).

أما إذا كان \(q>1\)، فيختار التنفيذ الأصغر بين \(a\) و\(b\) بوصفه طول الحلقة، ثم يحسب \(q^m\) مرة واحدة ويمر على \(j=1,\dots,k\). وخلال ذلك يضرب مجمعا في \(1-q^j\) ومجمعا آخر في \(1-q^{m+j}\)، مع الاختزال بترديد \(10^9+7\) بعد كل خطوة.

وبعد انتهاء الحلقة يضرب البسط المتراكم في المقلوب المعياري للمقام المتراكم. ثم تحسب الدالة العليا القيم السبع \(C(10^r+r,10^r+r,r)\) من أجل \(r=1,\dots,7\) وتجمعها تحت المود نفسه.

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

يتطلب حساب واحد لـ \(C(a,b,q)\) عندما \(q>1\) زمنا مقداره \(O(\min(a,b)+\log \max(a,b))\). يأتي الجزء اللوغاريتمي من رفع الأس المعياري، ويأتي الجزء الخطي من حلقة حاصل الضرب. أما الذاكرة الإضافية فهي \(O(1)\)، باستثناء الجدول الصغير الثابت المستخدم في فرع \(q=1\).

وفي المسألة 638 يكون العبء المسيطر هو مجموع أطوال الحلقات السبع:

$$\sum_{r=1}^{7}(10^r+r)=11{,}111{,}138.$$

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

حواشٍ ومراجع

  1. صفحة المسألة: https://projecteuler.net/problem=638
  2. معامل Gaussian الثنائي: Wikipedia - Gaussian binomial coefficient
  3. المسار الشبكي: Wikipedia - Lattice path
  4. المعكوس الضربي المعياري: Wikipedia - Modular multiplicative inverse
  5. مبرهنة فيرما الصغرى: Wikipedia - Fermat's little theorem