Problem Summary

For each \(n\in\{1,\dots,30\}\), let \(a_n\) be the largest real root of

$$x^3-2^n x^2+n=0.$$

The task is to compute

$$\sum_{n=1}^{30}\left\lfloor a_n^{987654321}\right\rfloor \pmod{10^8}.$$

A direct floating-point evaluation of such enormous powers would be fragile and unnecessary. The local C++, Python, and Java solutions instead turn the problem into an exact linear recurrence modulo \(10^8\).

Mathematical Approach

Step 1: Locate the Three Real Roots

Write \(c=2^n\) and \(f(x)=x^3-cx^2+n\). The implementations rely on the fact that the cubic has three real roots, with one large positive root and two small roots near the origin.

Indeed,

$$f(-1)=n-1-c<0,\qquad f(0)=n>0,$$

so there is a root \(\gamma\in(-1,0)\). Also,

$$f(1)=n+1-c\le 0,\qquad f(0)=n>0,$$

so there is a root \(\beta\in(0,1]\), with \(\beta=1\) only when \(n=1\). Finally,

$$f(c)=n>0,\qquad f(c-1)=n-(c-1)^2\le 0,$$

so the largest root \(\alpha=a_n\) lies in \((c-1,c)\). Thus the three roots satisfy

$$\gamma\in(-1,0),\qquad \beta\in(0,1],\qquad \alpha\in(2^n-1,2^n).$$

By Vieta's formulas,

$$\alpha+\beta+\gamma=c,\qquad \alpha\beta+\alpha\gamma+\beta\gamma=0,\qquad \alpha\beta\gamma=-n.$$

Step 2: Define the Power Sums

Let

$$S_k=\alpha^k+\beta^k+\gamma^k.$$

Because every root \(r\in\{\alpha,\beta,\gamma\}\) satisfies

$$r^3=cr^2-n,$$

multiplying by \(r^{k-3}\) gives

$$r^k=cr^{k-1}-nr^{k-3}\qquad (k\ge 3).$$

Summing over the three roots yields the recurrence used in every implementation:

$$\boxed{S_k=cS_{k-1}-nS_{k-3}\qquad (k\ge 3).}$$

The initial values are immediate:

$$S_0=3,$$

$$S_1=\alpha+\beta+\gamma=c,$$

$$S_2=(\alpha+\beta+\gamma)^2-2(\alpha\beta+\alpha\gamma+\beta\gamma)=c^2.$$

So the entire problem is reduced to a third-order linear recurrence.

Step 3: Why \(\left\lfloor a_n^m\right\rfloor=S_m-1\) for Odd \(m\)

Let \(m\) be odd and define the small-root contribution

$$\rho_m=\beta^m+\gamma^m.$$

Since \(\gamma<0\) and \(m\) is odd, we have \(\gamma^m<0\). We also know

$$\beta+\gamma=c-\alpha,$$

and because \(\alpha\in(c-1,c)\), this implies

$$0<\beta+\gamma<1.$$

In particular, \(\beta>|\gamma|\). For odd \(m\), monotonicity of \(x\mapsto x^m\) on positive numbers gives

$$\beta^m>|\gamma|^m,$$

hence

$$0<\rho_m=\beta^m-|\gamma|^m.$$

At the same time, \(\beta\le 1\) and \(|\gamma|<1\), so

$$\rho_m<1.$$

Therefore

$$0<\rho_m<1,$$

and since \(\alpha^m=S_m-\rho_m\), we obtain the crucial identity

$$\boxed{\left\lfloor \alpha^m\right\rfloor=\left\lfloor S_m-\rho_m\right\rfloor=S_m-1.}$$

This is exactly why the production code never needs to approximate \(a_n^{987654321}\) directly.

Step 4: Convert the Recurrence to Matrix Exponentiation

The recurrence has fixed order 3, so the state vector

$$\begin{bmatrix}S_k\\S_{k-1}\\S_{k-2}\end{bmatrix}$$

evolves by

$$\begin{bmatrix}S_k\\S_{k-1}\\S_{k-2}\end{bmatrix} = \begin{bmatrix} c & 0 & -n\\ 1 & 0 & 0\\ 0 & 1 & 0 \end{bmatrix} \begin{bmatrix}S_{k-1}\\S_{k-2}\\S_{k-3}\end{bmatrix}.$$

Hence, for \(m\ge 2\),

$$\begin{bmatrix}S_m\\S_{m-1}\\S_{m-2}\end{bmatrix} = M^{m-2} \begin{bmatrix}S_2\\S_1\\S_0\end{bmatrix}.$$

The solutions compute this power by binary exponentiation, reducing every multiplication modulo \(10^8\). In modular arithmetic the entry \(-n\) is stored as

$$10^8-(n\bmod 10^8),$$

which is why the source code writes the transition matrix with a non-negative last coefficient.

Step 5: A Small Checkpoint

Take \(n=2\), so \(c=4\). Then

$$S_0=3,\qquad S_1=4,\qquad S_2=16.$$

For the odd exponent \(m=3\), the recurrence gives

$$S_3=4\cdot 16-2\cdot 3=58.$$

Since \(0<\beta^3+\gamma^3<1\), we conclude

$$\left\lfloor a_2^3\right\rfloor=S_3-1=57.$$

The C++ implementation performs this kind of spot check numerically for small odd exponents before relying on the modular fast path for the full input.

How the Code Works

The three language versions all implement the same pipeline. First, powMod computes \(c=2^n\bmod 10^8\). Then multiplyMatrix and powerMatrix raise the \(3\times 3\) transition matrix to the power \(m-2\). The function computeNewtonSumMod returns \(S_m\bmod 10^8\), handling the base cases \(m=0,1,2\) directly and using matrix exponentiation otherwise.

After that, computeTermMod applies the identity \(\lfloor a_n^m\rfloor\equiv S_m-1\pmod{10^8}\), and solve sums the terms for \(n=1\) through \(30\). The longer C++ file also contains validation helpers: it checks the statement sample \(\lfloor a_2^2\rfloor=14\), verifies the matrix recurrence against a direct iterative recurrence, compares the floor identity against floating-point root calculations on small cases, and tests thread consistency. Those checks justify the method, but the final answer path itself is entirely integer-based.

Complexity Analysis

For one fixed \(n\), the dominant cost is exponentiating a \(3\times 3\) matrix to power \(m-2\), which takes \(O(\log m)\) matrix multiplications. The problem has only 30 values of \(n\), so the total running time is

$$O(30\log m)=O(\log m),$$

with \(O(1)\) auxiliary memory. The C++ version can parallelize the 30 independent \(n\)-values, but that changes only wall-clock time, not asymptotic complexity.

Footnotes and References

  1. Problem page: https://projecteuler.net/problem=356
  2. Vieta's formulas: Wikipedia - Vieta's formulas
  3. Newton sums / power sums: Wikipedia - Newton's identities
  4. Matrix exponentiation for linear recurrences: cp-algorithms - binary exponentiation of recurrence transitions

Problemzusammenfassung

Für jedes \(n\in\{1,\dots,30\}\) sei \(a_n\) die größte reelle Nullstelle von

$$x^3-2^n x^2+n=0.$$

Gesucht ist

$$\sum_{n=1}^{30}\left\lfloor a_n^{987654321}\right\rfloor \pmod{10^8}.$$

Eine direkte Auswertung der riesigen Potenzen mit Gleitkomma wäre unnötig unsauber. Die lokalen Lösungen in C++, Python und Java führen das Problem stattdessen auf eine exakte lineare Rekurrenz modulo \(10^8\) zurück.

Mathematischer Ansatz

Schritt 1: Lage der drei reellen Nullstellen

Setze \(c=2^n\) und \(f(x)=x^3-cx^2+n\). Die Implementierungen nutzen aus, dass das Polynom drei reelle Nullstellen besitzt: eine große positive und zwei kleine nahe dem Ursprung.

Es gilt

$$f(-1)=n-1-c<0,\qquad f(0)=n>0,$$

also existiert eine Nullstelle \(\gamma\in(-1,0)\). Außerdem

$$f(1)=n+1-c\le 0,\qquad f(0)=n>0,$$

daher gibt es eine Nullstelle \(\beta\in(0,1]\), wobei \(\beta=1\) nur für \(n=1\) auftritt. Schließlich

$$f(c)=n>0,\qquad f(c-1)=n-(c-1)^2\le 0,$$

also liegt die größte Nullstelle \(\alpha=a_n\) im Intervall \((c-1,c)\). Damit gilt

$$\gamma\in(-1,0),\qquad \beta\in(0,1],\qquad \alpha\in(2^n-1,2^n).$$

Mit den Formeln von Viète folgt

$$\alpha+\beta+\gamma=c,\qquad \alpha\beta+\alpha\gamma+\beta\gamma=0,\qquad \alpha\beta\gamma=-n.$$

Schritt 2: Potenzsummen definieren

Definiere

$$S_k=\alpha^k+\beta^k+\gamma^k.$$

Da jede Nullstelle \(r\in\{\alpha,\beta,\gamma\}\) die Gleichung

$$r^3=cr^2-n$$

erfüllt, erhält man nach Multiplikation mit \(r^{k-3}\)

$$r^k=cr^{k-1}-nr^{k-3}\qquad (k\ge 3).$$

Durch Summation über alle drei Nullstellen entsteht genau die Rekurrenz aus dem Quellcode:

$$\boxed{S_k=cS_{k-1}-nS_{k-3}\qquad (k\ge 3).}$$

Die Anfangswerte sind

$$S_0=3,$$

$$S_1=\alpha+\beta+\gamma=c,$$

$$S_2=(\alpha+\beta+\gamma)^2-2(\alpha\beta+\alpha\gamma+\beta\gamma)=c^2.$$

Damit ist das Problem auf eine lineare Rekurrenz dritter Ordnung reduziert.

Schritt 3: Warum bei ungeradem Exponenten \(\lfloor a_n^m\rfloor=S_m-1\) gilt

Für ungerades \(m\) definieren wir den Beitrag der kleinen Nullstellen als

$$\rho_m=\beta^m+\gamma^m.$$

Wegen \(\gamma<0\) und ungeradem \(m\) ist \(\gamma^m<0\). Außerdem gilt

$$\beta+\gamma=c-\alpha,$$

und aus \(\alpha\in(c-1,c)\) folgt

$$0<\beta+\gamma<1.$$

Insbesondere ist \(\beta>|\gamma|\). Für ungerades \(m\) folgt daraus

$$\beta^m>|\gamma|^m,$$

also

$$0<\rho_m=\beta^m-|\gamma|^m.$$

Zugleich gilt \(\beta\le 1\) und \(|\gamma|<1\), also

$$\rho_m<1.$$

Somit

$$0<\rho_m<1,$$

und da \(\alpha^m=S_m-\rho_m\), erhalten wir die Schlüsselformel

$$\boxed{\left\lfloor \alpha^m\right\rfloor=\left\lfloor S_m-\rho_m\right\rfloor=S_m-1.}$$

Genau deshalb berechnet der eigentliche Lösungsweg nie direkt \(a_n^{987654321}\).

Schritt 4: Matrixpotenzierung modulo \(10^8\)

Die Rekurrenz hat feste Ordnung 3. Deshalb entwickelt sich der Zustandsvektor

$$\begin{bmatrix}S_k\\S_{k-1}\\S_{k-2}\end{bmatrix}$$

nach der Vorschrift

$$\begin{bmatrix}S_k\\S_{k-1}\\S_{k-2}\end{bmatrix} = \begin{bmatrix} c & 0 & -n\\ 1 & 0 & 0\\ 0 & 1 & 0 \end{bmatrix} \begin{bmatrix}S_{k-1}\\S_{k-2}\\S_{k-3}\end{bmatrix}.$$

Für \(m\ge 2\) also

$$\begin{bmatrix}S_m\\S_{m-1}\\S_{m-2}\end{bmatrix} = M^{m-2} \begin{bmatrix}S_2\\S_1\\S_0\end{bmatrix}.$$

Der Code berechnet diese Potenz mit binärer Exponentiation. Da nur das Resultat modulo \(10^8\) benötigt wird, werden alle Operationen sofort reduziert. Der Eintrag \(-n\) wird im Code deshalb als nichtnegative Zahl

$$10^8-(n\bmod 10^8)$$

gespeichert.

Schritt 5: Kleiner Kontrollfall

Für \(n=2\) ist \(c=4\). Dann gilt

$$S_0=3,\qquad S_1=4,\qquad S_2=16.$$

Für den ungeraden Exponenten \(m=3\) liefert die Rekurrenz

$$S_3=4\cdot 16-2\cdot 3=58.$$

Da \(0<\beta^3+\gamma^3<1\), folgt

$$\left\lfloor a_2^3\right\rfloor=S_3-1=57.$$

Die C++-Version führt genau solche Stichproben für kleine ungerade Exponenten numerisch aus, bevor sie für den eigentlichen Lauf nur noch die modulare Schnellmethode verwendet.

Funktionsweise des Codes

Alle drei Sprachversionen benutzen dieselbe Struktur. Zuerst berechnet powMod den Wert \(c=2^n\bmod 10^8\). Danach heben multiplyMatrix und powerMatrix die \(3\times 3\)-Übergangsmatrix auf die Potenz \(m-2\). Die Funktion computeNewtonSumMod gibt \(S_m\bmod 10^8\) zurück; die Fälle \(m=0,1,2\) werden direkt behandelt, alle größeren Exponenten per Matrixpotenz.

Anschließend nutzt computeTermMod die Identität \(\lfloor a_n^m\rfloor\equiv S_m-1\pmod{10^8}\), und solve summiert über \(n=1,\dots,30\). Die ausführlichere C++-Datei enthält zusätzlich Validierungen: das Beispiel \(\lfloor a_2^2\rfloor=14\), einen Vergleich zwischen Matrix- und iterativer Rekurrenz, numerische Prüfungen der Bodenfunktion für kleine Fälle und einen Thread-Konsistenztest. Der eigentliche Rechenweg bleibt aber vollständig ganzzahlig.

Komplexitätsanalyse

Für ein festes \(n\) dominiert die Potenzierung einer \(3\times 3\)-Matrix auf die Höhe \(m-2\). Das kostet \(O(\log m)\) Matrixmultiplikationen. Da nur 30 Werte von \(n\) vorkommen, beträgt die Gesamtlaufzeit

$$O(30\log m)=O(\log m),$$

bei \(O(1)\) Zusatzspeicher. Die C++-Implementierung kann die 30 unabhängigen \(n\)-Werte parallel auswerten; an der asymptotischen Ordnung ändert das nichts.

Fußnoten und Quellen

  1. Problemseite: https://projecteuler.net/problem=356
  2. Formeln von Viète: Wikipedia - Vieta's formulas
  3. Newton-Summen und Potenzsummen: Wikipedia - Newton's identities
  4. Matrixpotenzierung für lineare Rekurrenzen: cp-algorithms - binary exponentiation of recurrence transitions

Problem Özeti

Her \(n\in\{1,\dots,30\}\) için \(a_n\),

$$x^3-2^n x^2+n=0$$

denkleminin en büyük gerçek kökü olsun. İstenen değer

$$\sum_{n=1}^{30}\left\lfloor a_n^{987654321}\right\rfloor \pmod{10^8}$$

ifadesidir. Bu kadar büyük üsler için doğrudan kayan noktalı hesap yapmak hem gereksiz hem de risklidir. Yerel C++, Python ve Java çözümleri bunun yerine problemi \(10^8\) modunda çalışan kesin bir lineer reküransa indirger.

Matematiksel Yaklaşım

Adım 1: Üç Gerçek Kökün Konumu

\(c=2^n\) ve \(f(x)=x^3-cx^2+n\) olsun. Uygulama, bu kübiğin üç gerçek kökü olmasını kullanır: biri büyük pozitif, ikisi ise orijine yakın küçük köklerdir.

Gerçekten,

$$f(-1)=n-1-c<0,\qquad f(0)=n>0,$$

olduğu için \(\gamma\in(-1,0)\) aralığında bir kök vardır. Ayrıca

$$f(1)=n+1-c\le 0,\qquad f(0)=n>0,$$

olduğundan \(\beta\in(0,1]\) aralığında bir kök bulunur; \(\beta=1\) yalnızca \(n=1\) için oluşur. Son olarak

$$f(c)=n>0,\qquad f(c-1)=n-(c-1)^2\le 0,$$

olduğu için en büyük kök \(\alpha=a_n\), \((c-1,c)\) aralığındadır. Dolayısıyla

$$\gamma\in(-1,0),\qquad \beta\in(0,1],\qquad \alpha\in(2^n-1,2^n).$$

Vieta bağıntıları da şunları verir:

$$\alpha+\beta+\gamma=c,\qquad \alpha\beta+\alpha\gamma+\beta\gamma=0,\qquad \alpha\beta\gamma=-n.$$

Adım 2: Kuvvet Toplamları

Şimdi

$$S_k=\alpha^k+\beta^k+\gamma^k$$

tanımını yapalım. Her kök \(r\in\{\alpha,\beta,\gamma\}\) için

$$r^3=cr^2-n$$

geçerlidir. Bunu \(r^{k-3}\) ile çarparsak

$$r^k=cr^{k-1}-nr^{k-3}\qquad (k\ge 3)$$

elde ederiz. Üç kök üzerinde toplandığında, çözümlerde kullanılan rekürans ortaya çıkar:

$$\boxed{S_k=cS_{k-1}-nS_{k-3}\qquad (k\ge 3).}$$

Başlangıç değerleri ise

$$S_0=3,$$

$$S_1=\alpha+\beta+\gamma=c,$$

$$S_2=(\alpha+\beta+\gamma)^2-2(\alpha\beta+\alpha\gamma+\beta\gamma)=c^2.$$

Böylece problem üçüncü dereceden lineer bir reküransa dönüşür.

Adım 3: Tek \(m\) için neden \(\lfloor a_n^m\rfloor=S_m-1\)

\(m\) tek olsun ve küçük köklerin katkısını

$$\rho_m=\beta^m+\gamma^m$$

olarak tanımlayalım. \(\gamma<0\) ve \(m\) tek olduğundan \(\gamma^m<0\). Ayrıca

$$\beta+\gamma=c-\alpha$$

olup \(\alpha\in(c-1,c)\) nedeniyle

$$0<\beta+\gamma<1.$$

Buradan \(\beta>|\gamma|\) çıkar. Tek kuvvette bu sıralama korunur:

$$\beta^m>|\gamma|^m,$$

dolayısıyla

$$0<\rho_m=\beta^m-|\gamma|^m.$$

Öte yandan \(\beta\le 1\) ve \(|\gamma|<1\) olduğundan

$$\rho_m<1.$$

Sonuç olarak

$$0<\rho_m<1,$$

ve \(\alpha^m=S_m-\rho_m\) eşitliğinden şu temel kimlik elde edilir:

$$\boxed{\left\lfloor \alpha^m\right\rfloor=\left\lfloor S_m-\rho_m\right\rfloor=S_m-1.}$$

Bu yüzden üretim yolunda \(a_n^{987654321}\) doğrudan hesaplanmaz.

Adım 4: Reküransı Matris Üslemesine Çevirmek

Reküransın derecesi sabit olarak 3'tür. Bu nedenle durum vektörü

$$\begin{bmatrix}S_k\\S_{k-1}\\S_{k-2}\end{bmatrix}$$

şu geçişle ilerler:

$$\begin{bmatrix}S_k\\S_{k-1}\\S_{k-2}\end{bmatrix} = \begin{bmatrix} c & 0 & -n\\ 1 & 0 & 0\\ 0 & 1 & 0 \end{bmatrix} \begin{bmatrix}S_{k-1}\\S_{k-2}\\S_{k-3}\end{bmatrix}.$$

Dolayısıyla \(m\ge 2\) için

$$\begin{bmatrix}S_m\\S_{m-1}\\S_{m-2}\end{bmatrix} = M^{m-2} \begin{bmatrix}S_2\\S_1\\S_0\end{bmatrix}.$$

Kod bu kuvveti ikili üs alma ile hesaplar ve her çarpımı hemen \(10^8\) moduna indirger. Modüler aritmetikte \(-n\) katsayısı, kaynak kodda

$$10^8-(n\bmod 10^8)$$

olarak saklanır; bu yüzden geçiş matrisinde negatif sayı görülmez.

Adım 5: Küçük Bir Kontrol Örneği

\(n=2\) için \(c=4\) olur. O halde

$$S_0=3,\qquad S_1=4,\qquad S_2=16.$$

Tek üs \(m=3\) için rekürans

$$S_3=4\cdot 16-2\cdot 3=58$$

sonucunu verir. \(0<\beta^3+\gamma^3<1\) olduğundan

$$\left\lfloor a_2^3\right\rfloor=S_3-1=57.$$

C++ çözümü, tam hızlı yola güvenmeden önce küçük tek üsler için buna benzer sayısal doğrulamalar yapar.

Kodun Çalışma Mantığı

Üç dildeki çözüm de aynı akışı izler. Önce powMod, \(c=2^n\bmod 10^8\) değerini hesaplar. Sonra multiplyMatrix ve powerMatrix, \(3\times 3\) geçiş matrisini \(m-2\) kuvvetine yükseltir. computeNewtonSumMod fonksiyonu \(S_m\bmod 10^8\) döndürür; \(m=0,1,2\) durumları doğrudan ele alınır, daha büyük üslerde matris üsleme kullanılır.

Ardından computeTermMod, \(\lfloor a_n^m\rfloor\equiv S_m-1\pmod{10^8}\) kimliğini uygular ve solve fonksiyonu \(n=1\) ile \(30\) arasındaki tüm terimleri toplar. Daha uzun olan C++ dosyası ayrıca birkaç doğrulama içerir: \(\lfloor a_2^2\rfloor=14\) örneği, matrisli ve iteratif reküransın karşılaştırılması, küçük örneklerde sayısal kök denetimi ve çok iş parçacıklı tutarlılık testi. Ancak nihai hesap yolu tamamen tamsayı aritmetiğine dayanır.

Karmaşıklık Analizi

Sabit bir \(n\) için baskın işlem, \(3\times 3\) matrisin \(m-2\) kuvvetine çıkarılmasıdır; bu da \(O(\log m)\) adet matris çarpımı gerektirir. Problemde yalnızca 30 farklı \(n\) bulunduğu için toplam süre

$$O(30\log m)=O(\log m)$$

olur ve ek bellek \(O(1)\) düzeyindedir. C++ sürümü bağımsız \(n\) değerlerini paralel çalıştırabilir; bu yalnızca pratik süreyi düşürür, matematiksel karmaşıklığı değiştirmez.

Dipnotlar ve Kaynakça

  1. Problem sayfası: https://projecteuler.net/problem=356
  2. Vieta bağıntıları: Wikipedia - Vieta's formulas
  3. Newton özdeşlikleri ve kuvvet toplamları: Wikipedia - Newton's identities
  4. Lineer reküranslar için matris üs alma: cp-algorithms - binary exponentiation of recurrence transitions

Resumen del Problema

Para cada \(n\in\{1,\dots,30\}\), sea \(a_n\) la mayor raíz real de

$$x^3-2^n x^2+n=0.$$

Hay que calcular

$$\sum_{n=1}^{30}\left\lfloor a_n^{987654321}\right\rfloor \pmod{10^8}.$$

Evaluar esas potencias gigantes con aritmética de punto flotante sería frágil e innecesario. Las soluciones locales en C++, Python y Java transforman el problema en una recurrencia lineal exacta módulo \(10^8\).

Enfoque Matemático

Paso 1: Ubicación de las tres raíces reales

Escribamos \(c=2^n\) y \(f(x)=x^3-cx^2+n\). La idea central es que el cúbico tiene tres raíces reales: una grande y positiva, y dos pequeñas cerca del origen.

Se tiene

$$f(-1)=n-1-c<0,\qquad f(0)=n>0,$$

así que existe una raíz \(\gamma\in(-1,0)\). Además,

$$f(1)=n+1-c\le 0,\qquad f(0)=n>0,$$

por lo que existe una raíz \(\beta\in(0,1]\), con \(\beta=1\) solo cuando \(n=1\). Finalmente,

$$f(c)=n>0,\qquad f(c-1)=n-(c-1)^2\le 0,$$

de modo que la raíz mayor \(\alpha=a_n\) pertenece a \((c-1,c)\). En resumen,

$$\gamma\in(-1,0),\qquad \beta\in(0,1],\qquad \alpha\in(2^n-1,2^n).$$

Las fórmulas de Viète dan

$$\alpha+\beta+\gamma=c,\qquad \alpha\beta+\alpha\gamma+\beta\gamma=0,\qquad \alpha\beta\gamma=-n.$$

Paso 2: Sumas de potencias

Definimos

$$S_k=\alpha^k+\beta^k+\gamma^k.$$

Cada raíz \(r\in\{\alpha,\beta,\gamma\}\) satisface

$$r^3=cr^2-n,$$

y al multiplicar por \(r^{k-3}\) obtenemos

$$r^k=cr^{k-1}-nr^{k-3}\qquad (k\ge 3).$$

Sumando sobre las tres raíces aparece exactamente la recurrencia usada en el código:

$$\boxed{S_k=cS_{k-1}-nS_{k-3}\qquad (k\ge 3).}$$

Los valores iniciales son

$$S_0=3,$$

$$S_1=\alpha+\beta+\gamma=c,$$

$$S_2=(\alpha+\beta+\gamma)^2-2(\alpha\beta+\alpha\gamma+\beta\gamma)=c^2.$$

Así, el problema queda reducido a una recurrencia lineal de orden 3.

Paso 3: Por qué \(\lfloor a_n^m\rfloor=S_m-1\) cuando \(m\) es impar

Para \(m\) impar, definimos la contribución de las raíces pequeñas

$$\rho_m=\beta^m+\gamma^m.$$

Como \(\gamma<0\) y \(m\) es impar, \(\gamma^m<0\). Además,

$$\beta+\gamma=c-\alpha,$$

y puesto que \(\alpha\in(c-1,c)\), se sigue que

$$0<\beta+\gamma<1.$$

En particular, \(\beta>|\gamma|\). Para exponentes impares eso implica

$$\beta^m>|\gamma|^m,$$

de modo que

$$0<\rho_m=\beta^m-|\gamma|^m.$$

Por otra parte, \(\beta\le 1\) y \(|\gamma|<1\), así que

$$\rho_m<1.$$

En consecuencia,

$$0<\rho_m<1,$$

y como \(\alpha^m=S_m-\rho_m\), obtenemos la identidad clave

$$\boxed{\left\lfloor \alpha^m\right\rfloor=\left\lfloor S_m-\rho_m\right\rfloor=S_m-1.}$$

Esa es la razón por la que el camino rápido nunca calcula directamente \(a_n^{987654321}\).

Paso 4: Potenciación matricial

La recurrencia tiene orden fijo 3, por lo que el vector de estado

$$\begin{bmatrix}S_k\\S_{k-1}\\S_{k-2}\end{bmatrix}$$

evoluciona según

$$\begin{bmatrix}S_k\\S_{k-1}\\S_{k-2}\end{bmatrix} = \begin{bmatrix} c & 0 & -n\\ 1 & 0 & 0\\ 0 & 1 & 0 \end{bmatrix} \begin{bmatrix}S_{k-1}\\S_{k-2}\\S_{k-3}\end{bmatrix}.$$

Por tanto, para \(m\ge 2\),

$$\begin{bmatrix}S_m\\S_{m-1}\\S_{m-2}\end{bmatrix} = M^{m-2} \begin{bmatrix}S_2\\S_1\\S_0\end{bmatrix}.$$

El programa calcula esa potencia con exponenciación binaria y reduce todo módulo \(10^8\). En aritmética modular, el coeficiente \(-n\) se almacena como

$$10^8-(n\bmod 10^8),$$

que es exactamente lo que aparece en las implementaciones.

Paso 5: Comprobación pequeña

Tomemos \(n=2\), de modo que \(c=4\). Entonces

$$S_0=3,\qquad S_1=4,\qquad S_2=16.$$

Para el exponente impar \(m=3\), la recurrencia produce

$$S_3=4\cdot 16-2\cdot 3=58.$$

Como \(0<\beta^3+\gamma^3<1\), concluimos que

$$\left\lfloor a_2^3\right\rfloor=S_3-1=57.$$

La versión en C++ hace este tipo de comprobaciones numéricas en casos pequeños antes de ejecutar el cálculo modular completo.

Cómo Funciona el Código

Las tres versiones usan la misma estructura. Primero, powMod calcula \(c=2^n\bmod 10^8\). Luego, multiplyMatrix y powerMatrix elevan la matriz de transición \(3\times 3\) a la potencia \(m-2\). La función computeNewtonSumMod devuelve \(S_m\bmod 10^8\), tratando de forma directa los casos \(m=0,1,2\) y usando potenciación matricial para el resto.

Después, computeTermMod aplica la identidad \(\lfloor a_n^m\rfloor\equiv S_m-1\pmod{10^8}\), y solve suma los 30 términos. El archivo C++ añade validaciones auxiliares: comprueba el ejemplo \(\lfloor a_2^2\rfloor=14\), verifica la recurrencia matricial contra una versión iterativa, contrasta la identidad del piso con cálculos numéricos de raíces en casos pequeños y revisa la consistencia entre un hilo y varios. El camino final, sin embargo, usa solo aritmética entera.

Complejidad

Para un \(n\) fijo, el coste dominante es elevar una matriz \(3\times 3\) a la potencia \(m-2\), lo que requiere \(O(\log m)\) multiplicaciones matriciales. Como solo hay 30 valores de \(n\), el coste total es

$$O(30\log m)=O(\log m),$$

con memoria auxiliar \(O(1)\). La versión en C++ puede paralelizar los valores de \(n\), pero eso solo mejora el tiempo real de ejecución.

Notas y Referencias

  1. Página del problema: https://projecteuler.net/problem=356
  2. Fórmulas de Viète: Wikipedia - Vieta's formulas
  3. Identidades de Newton y sumas de potencias: Wikipedia - Newton's identities
  4. Exponenciación matricial para recurrencias lineales: cp-algorithms - binary exponentiation of recurrence transitions

问题概述

对每个 \(n\in\{1,\dots,30\}\),令 \(a_n\) 为方程

$$x^3-2^n x^2+n=0$$

的最大实根。题目要求计算

$$\sum_{n=1}^{30}\left\lfloor a_n^{987654321}\right\rfloor \pmod{10^8}.$$

如果直接用浮点数去计算如此巨大的幂,既不稳定也没有必要。仓库里的 C++、Python 和 Java 解法都把问题改写成一个在 \(10^8\) 模意义下精确运行的线性递推。

数学方法

第一步:确定三个实根的位置

记 \(c=2^n\),并设 \(f(x)=x^3-cx^2+n\)。实现所依赖的关键事实是:这个三次多项式有三个实根,其中一个是接近 \(2^n\) 的大正根,另外两个都靠近原点。

因为

$$f(-1)=n-1-c<0,\qquad f(0)=n>0,$$

所以存在一个根 \(\gamma\in(-1,0)\)。又因为

$$f(1)=n+1-c\le 0,\qquad f(0)=n>0,$$

所以存在一个根 \(\beta\in(0,1]\),且只有在 \(n=1\) 时才会出现 \(\beta=1\)。最后,

$$f(c)=n>0,\qquad f(c-1)=n-(c-1)^2\le 0,$$

因此最大实根 \(\alpha=a_n\) 落在 \((c-1,c)\) 内。于是三根满足

$$\gamma\in(-1,0),\qquad \beta\in(0,1],\qquad \alpha\in(2^n-1,2^n).$$

再由 Viète 关系可得

$$\alpha+\beta+\gamma=c,\qquad \alpha\beta+\alpha\gamma+\beta\gamma=0,\qquad \alpha\beta\gamma=-n.$$

第二步:构造幂和递推

定义

$$S_k=\alpha^k+\beta^k+\gamma^k.$$

每个根 \(r\in\{\alpha,\beta,\gamma\}\) 都满足

$$r^3=cr^2-n.$$

两边乘以 \(r^{k-3}\) 得到

$$r^k=cr^{k-1}-nr^{k-3}\qquad (k\ge 3).$$

对三个根求和,就得到代码真正使用的递推式:

$$\boxed{S_k=cS_{k-1}-nS_{k-3}\qquad (k\ge 3).}$$

初值同样很简单:

$$S_0=3,$$

$$S_1=\alpha+\beta+\gamma=c,$$

$$S_2=(\alpha+\beta+\gamma)^2-2(\alpha\beta+\alpha\gamma+\beta\gamma)=c^2.$$

这样,原问题就变成了一个三阶线性递推问题。

第三步:为什么奇数次幂时 \(\lfloor a_n^m\rfloor=S_m-1\)

设 \(m\) 为奇数,并记小根的贡献为

$$\rho_m=\beta^m+\gamma^m.$$

由于 \(\gamma<0\) 且 \(m\) 为奇数,所以 \(\gamma^m<0\)。另一方面,

$$\beta+\gamma=c-\alpha,$$

而 \(\alpha\in(c-1,c)\) 说明

$$0<\beta+\gamma<1.$$

因此 \(\beta>|\gamma|\)。对奇数次幂,这意味着

$$\beta^m>|\gamma|^m,$$

从而

$$0<\rho_m=\beta^m-|\gamma|^m.$$

同时 \(\beta\le 1\) 且 \(|\gamma|<1\),所以

$$\rho_m<1.$$

于是得到

$$0<\rho_m<1,$$

并且因为 \(\alpha^m=S_m-\rho_m\),便有关键恒等式

$$\boxed{\left\lfloor \alpha^m\right\rfloor=\left\lfloor S_m-\rho_m\right\rfloor=S_m-1.}$$

这就是为什么正式解法完全不需要直接求 \(a_n^{987654321}\)。

第四步:用矩阵快速幂求递推

因为递推阶数固定为 3,所以状态向量

$$\begin{bmatrix}S_k\\S_{k-1}\\S_{k-2}\end{bmatrix}$$

满足

$$\begin{bmatrix}S_k\\S_{k-1}\\S_{k-2}\end{bmatrix} = \begin{bmatrix} c & 0 & -n\\ 1 & 0 & 0\\ 0 & 1 & 0 \end{bmatrix} \begin{bmatrix}S_{k-1}\\S_{k-2}\\S_{k-3}\end{bmatrix}.$$

因此当 \(m\ge 2\) 时,

$$\begin{bmatrix}S_m\\S_{m-1}\\S_{m-2}\end{bmatrix} = M^{m-2} \begin{bmatrix}S_2\\S_1\\S_0\end{bmatrix}.$$

代码用二进制快速幂来计算 \(M^{m-2}\),并且每一步都对 \(10^8\) 取模。在模运算中,系数 \(-n\) 会被写成

$$10^8-(n\bmod 10^8),$$

这正是实现里看到的非负写法。

第五步:一个小型校验

取 \(n=2\),此时 \(c=4\)。那么

$$S_0=3,\qquad S_1=4,\qquad S_2=16.$$

对于奇数指数 \(m=3\),递推给出

$$S_3=4\cdot 16-2\cdot 3=58.$$

又因为 \(0<\beta^3+\gamma^3<1\),所以

$$\left\lfloor a_2^3\right\rfloor=S_3-1=57.$$

C++ 版本在进入正式的大规模模运算之前,会先用这种小案例做数值核对。

代码原理

三种语言的实现结构完全一致。首先,powMod 计算 \(c=2^n\bmod 10^8\)。然后,multiplyMatrixpowerMatrix 对 \(3\times 3\) 转移矩阵做快速幂。函数 computeNewtonSumMod 返回 \(S_m\bmod 10^8\):当 \(m=0,1,2\) 时直接返回初值,更大的指数则通过矩阵幂得到。

接着,computeTermMod 利用 \(\lfloor a_n^m\rfloor\equiv S_m-1\pmod{10^8}\) 这一结论,solve 再把 \(n=1\) 到 \(30\) 的结果累加起来。较长的 C++ 文件还包含几项验证逻辑:检查题目中的样例 \(\lfloor a_2^2\rfloor=14\),比较矩阵递推与迭代递推,验证小规模奇数幂下的取整恒等式,以及测试多线程结果是否一致。不过真正的快速路径始终只使用整数运算。

复杂度分析

对固定的 \(n\) 来说,主要成本是把 \(3\times 3\) 矩阵提升到 \(m-2\) 次幂,这需要 \(O(\log m)\) 次矩阵乘法。题目只需要处理 30 个 \(n\),所以总时间复杂度为

$$O(30\log m)=O(\log m),$$

额外空间复杂度为 \(O(1)\)。C++ 版本可以把不同的 \(n\) 并行计算,但这只影响实际运行时间,不改变复杂度级别。

参考资料

  1. 题目页面: https://projecteuler.net/problem=356
  2. Viète 公式: Wikipedia - Vieta's formulas
  3. Newton 恒等式与幂和: Wikipedia - Newton's identities
  4. 线性递推的矩阵快速幂: cp-algorithms - binary exponentiation of recurrence transitions

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

Для каждого \(n\in\{1,\dots,30\}\) обозначим через \(a_n\) наибольший действительный корень уравнения

$$x^3-2^n x^2+n=0.$$

Нужно вычислить

$$\sum_{n=1}^{30}\left\lfloor a_n^{987654321}\right\rfloor \pmod{10^8}.$$

Напрямую поднимать корни в такую огромную степень с плавающей точкой было бы и медленно, и ненадежно. Локальные решения на C++, Python и Java сводят задачу к точной линейной рекурсии по модулю \(10^8\).

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

Шаг 1: Расположение трех действительных корней

Положим \(c=2^n\) и \(f(x)=x^3-cx^2+n\). Ключевой факт состоит в том, что у этого кубического многочлена три действительных корня: один большой положительный и два малых около нуля.

Имеем

$$f(-1)=n-1-c<0,\qquad f(0)=n>0,$$

значит, существует корень \(\gamma\in(-1,0)\). Далее,

$$f(1)=n+1-c\le 0,\qquad f(0)=n>0,$$

поэтому существует корень \(\beta\in(0,1]\), причем \(\beta=1\) только при \(n=1\). Наконец,

$$f(c)=n>0,\qquad f(c-1)=n-(c-1)^2\le 0,$$

следовательно, наибольший корень \(\alpha=a_n\) лежит в интервале \((c-1,c)\). Итак,

$$\gamma\in(-1,0),\qquad \beta\in(0,1],\qquad \alpha\in(2^n-1,2^n).$$

По формулам Виета:

$$\alpha+\beta+\gamma=c,\qquad \alpha\beta+\alpha\gamma+\beta\gamma=0,\qquad \alpha\beta\gamma=-n.$$

Шаг 2: Суммы степеней

Введем

$$S_k=\alpha^k+\beta^k+\gamma^k.$$

Каждый корень \(r\in\{\alpha,\beta,\gamma\}\) удовлетворяет равенству

$$r^3=cr^2-n.$$

Умножая его на \(r^{k-3}\), получаем

$$r^k=cr^{k-1}-nr^{k-3}\qquad (k\ge 3).$$

Суммирование по трем корням дает рекурсию, которая и реализована в коде:

$$\boxed{S_k=cS_{k-1}-nS_{k-3}\qquad (k\ge 3).}$$

Начальные значения таковы:

$$S_0=3,$$

$$S_1=\alpha+\beta+\gamma=c,$$

$$S_2=(\alpha+\beta+\gamma)^2-2(\alpha\beta+\alpha\gamma+\beta\gamma)=c^2.$$

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

Шаг 3: Почему для нечетного \(m\) верно \(\lfloor a_n^m\rfloor=S_m-1\)

Пусть \(m\) нечетно, и обозначим вклад малых корней через

$$\rho_m=\beta^m+\gamma^m.$$

Так как \(\gamma<0\) и \(m\) нечетно, имеем \(\gamma^m<0\). Кроме того,

$$\beta+\gamma=c-\alpha,$$

а из \(\alpha\in(c-1,c)\) следует

$$0<\beta+\gamma<1.$$

Значит, \(\beta>|\gamma|\). Для нечетной степени получаем

$$\beta^m>|\gamma|^m,$$

и потому

$$0<\rho_m=\beta^m-|\gamma|^m.$$

С другой стороны, \(\beta\le 1\) и \(|\gamma|<1\), следовательно,

$$\rho_m<1.$$

Итак,

$$0<\rho_m<1,$$

а поскольку \(\alpha^m=S_m-\rho_m\), получаем основное тождество

$$\boxed{\left\lfloor \alpha^m\right\rfloor=\left\lfloor S_m-\rho_m\right\rfloor=S_m-1.}$$

Именно поэтому быстрый путь решения не вычисляет \(a_n^{987654321}\) напрямую.

Шаг 4: Матричное возведение в степень

Рекурсия имеет фиксированный порядок 3, поэтому вектор состояния

$$\begin{bmatrix}S_k\\S_{k-1}\\S_{k-2}\end{bmatrix}$$

эволюционирует по правилу

$$\begin{bmatrix}S_k\\S_{k-1}\\S_{k-2}\end{bmatrix} = \begin{bmatrix} c & 0 & -n\\ 1 & 0 & 0\\ 0 & 1 & 0 \end{bmatrix} \begin{bmatrix}S_{k-1}\\S_{k-2}\\S_{k-3}\end{bmatrix}.$$

Следовательно, при \(m\ge 2\)

$$\begin{bmatrix}S_m\\S_{m-1}\\S_{m-2}\end{bmatrix} = M^{m-2} \begin{bmatrix}S_2\\S_1\\S_0\end{bmatrix}.$$

Программа вычисляет эту степень бинарным возведением, каждый раз сокращая результат по модулю \(10^8\). Коэффициент \(-n\) в модульной арифметике хранится как

$$10^8-(n\bmod 10^8),$$

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

Шаг 5: Небольшой контрольный пример

Возьмем \(n=2\), тогда \(c=4\). Получаем

$$S_0=3,\qquad S_1=4,\qquad S_2=16.$$

Для нечетного показателя \(m=3\) рекурсия дает

$$S_3=4\cdot 16-2\cdot 3=58.$$

Так как \(0<\beta^3+\gamma^3<1\), отсюда следует

$$\left\lfloor a_2^3\right\rfloor=S_3-1=57.$$

В C++-версии именно такие малые проверки используются как валидация перед основным модульным вычислением.

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

Во всех трех языках логика одна и та же. Сначала функция powMod вычисляет \(c=2^n\bmod 10^8\). Затем multiplyMatrix и powerMatrix возводят переходную матрицу \(3\times 3\) в степень \(m-2\). Функция computeNewtonSumMod возвращает \(S_m\bmod 10^8\): случаи \(m=0,1,2\) обрабатываются напрямую, для больших показателей используется матричное возведение.

После этого computeTermMod применяет тождество \(\lfloor a_n^m\rfloor\equiv S_m-1\pmod{10^8}\), а solve суммирует значения по \(n=1,\dots,30\). Более длинный файл на C++ также содержит проверки: пример из условия \(\lfloor a_2^2\rfloor=14\), сравнение матричной и итеративной рекурсий, численную проверку тождества пола на малых случаях и тест согласованности однопоточного и многопоточного режимов. Но сам быстрый путь полностью целочисленный.

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

Для фиксированного \(n\) основная стоимость состоит в возведении матрицы \(3\times 3\) в степень \(m-2\), что требует \(O(\log m)\) матричных умножений. Так как значений \(n\) всего 30, итоговая сложность равна

$$O(30\log m)=O(\log m),$$

а дополнительная память составляет \(O(1)\). Версия на C++ может распараллелить независимые значения \(n\), но это меняет только практическое время работы.

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

  1. Страница задачи: https://projecteuler.net/problem=356
  2. Формулы Виета: Wikipedia - Vieta's formulas
  3. Тождества Ньютона и суммы степеней: Wikipedia - Newton's identities
  4. Матричное ускорение линейных рекурсий: cp-algorithms - binary exponentiation of recurrence transitions

ملخص المسألة

لكل \(n\in\{1,\dots,30\}\)، ليكن \(a_n\) أكبر جذر حقيقي للمعادلة

$$x^3-2^n x^2+n=0.$$

المطلوب حساب

$$\sum_{n=1}^{30}\left\lfloor a_n^{987654321}\right\rfloor \pmod{10^8}.$$

رفع هذه الجذور إلى أس هائل مباشرة باستخدام الأعداد العائمة ليس خيارًا جيدًا. الحلول المحلية في C++ وPython وJava تحوّل المسألة إلى علاقة عودية خطية دقيقة تعمل مباشرة تحت المودولو \(10^8\).

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

الخطوة 1: مواضع الجذور الحقيقية الثلاثة

لنكتب \(c=2^n\) و\(f(x)=x^3-cx^2+n\). الفكرة الأساسية في التنفيذ أن هذا كثير الحدود التكعيبي يملك ثلاثة جذور حقيقية: جذرًا موجبًا كبيرًا، وجذرين صغيرين قريبين من الصفر.

لدينا

$$f(-1)=n-1-c<0,\qquad f(0)=n>0,$$

ومن ثم يوجد جذر \(\gamma\in(-1,0)\). كذلك

$$f(1)=n+1-c\le 0,\qquad f(0)=n>0,$$

لذلك يوجد جذر \(\beta\in(0,1]\)، وتكون \(\beta=1\) فقط عندما \(n=1\). وأخيرًا

$$f(c)=n>0,\qquad f(c-1)=n-(c-1)^2\le 0,$$

ولهذا يقع أكبر جذر \(\alpha=a_n\) داخل الفترة \((c-1,c)\). إذن

$$\gamma\in(-1,0),\qquad \beta\in(0,1],\qquad \alpha\in(2^n-1,2^n).$$

ومن علاقات فييتا نحصل على

$$\alpha+\beta+\gamma=c,\qquad \alpha\beta+\alpha\gamma+\beta\gamma=0,\qquad \alpha\beta\gamma=-n.$$

الخطوة 2: مجاميع القوى

نعرّف

$$S_k=\alpha^k+\beta^k+\gamma^k.$$

كل جذر \(r\in\{\alpha,\beta,\gamma\}\) يحقق

$$r^3=cr^2-n.$$

وبعد الضرب في \(r^{k-3}\) نحصل على

$$r^k=cr^{k-1}-nr^{k-3}\qquad (k\ge 3).$$

وبالجمع على الجذور الثلاثة تظهر نفس العلاقة العودية الموجودة في الشيفرة:

$$\boxed{S_k=cS_{k-1}-nS_{k-3}\qquad (k\ge 3).}$$

أما القيم الابتدائية فهي

$$S_0=3,$$

$$S_1=\alpha+\beta+\gamma=c,$$

$$S_2=(\alpha+\beta+\gamma)^2-2(\alpha\beta+\alpha\gamma+\beta\gamma)=c^2.$$

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

الخطوة 3: لماذا \(\lfloor a_n^m\rfloor=S_m-1\) عندما يكون \(m\) فرديًا

لنفرض أن \(m\) فردي، ولنعرف مساهمة الجذرين الصغيرين بالكمية

$$\rho_m=\beta^m+\gamma^m.$$

بما أن \(\gamma<0\) و\(m\) فردي، فإن \(\gamma^m<0\). كذلك لدينا

$$\beta+\gamma=c-\alpha,$$

ومع \(\alpha\in(c-1,c)\) ينتج

$$0<\beta+\gamma<1.$$

إذًا \(\beta>|\gamma|\). وللأس الفردي نحصل على

$$\beta^m>|\gamma|^m,$$

ومن ثم

$$0<\rho_m=\beta^m-|\gamma|^m.$$

وفي الوقت نفسه \(\beta\le 1\) و\(|\gamma|<1\)، ولذلك

$$\rho_m<1.$$

إذن

$$0<\rho_m<1,$$

وبما أن \(\alpha^m=S_m-\rho_m\)، نحصل على الهوية الأساسية

$$\boxed{\left\lfloor \alpha^m\right\rfloor=\left\lfloor S_m-\rho_m\right\rfloor=S_m-1.}$$

ولهذا لا يحتاج المسار السريع في الحل إلى حساب \(a_n^{987654321}\) مباشرة.

الخطوة 4: أس المصفوفة

بما أن العلاقة العودية من الرتبة 3، فإن متجه الحالة

$$\begin{bmatrix}S_k\\S_{k-1}\\S_{k-2}\end{bmatrix}$$

يتطور وفقًا لـ

$$\begin{bmatrix}S_k\\S_{k-1}\\S_{k-2}\end{bmatrix} = \begin{bmatrix} c & 0 & -n\\ 1 & 0 & 0\\ 0 & 1 & 0 \end{bmatrix} \begin{bmatrix}S_{k-1}\\S_{k-2}\\S_{k-3}\end{bmatrix}.$$

ومن ثم عندما \(m\ge 2\)،

$$\begin{bmatrix}S_m\\S_{m-1}\\S_{m-2}\end{bmatrix} = M^{m-2} \begin{bmatrix}S_2\\S_1\\S_0\end{bmatrix}.$$

تحسب الشيفرة هذه القوة بالرفع الثنائي، مع أخذ كل عملية تحت المودولو \(10^8\). ولهذا يُخزَّن المعامل \(-n\) في الصورة

$$10^8-(n\bmod 10^8),$$

بدلًا من استعمال عدد سالب داخل المصفوفة.

الخطوة 5: فحص صغير

خذ \(n=2\)، وعندها يكون \(c=4\). إذن

$$S_0=3,\qquad S_1=4,\qquad S_2=16.$$

وللأس الفردي \(m=3\) تعطي العلاقة العودية

$$S_3=4\cdot 16-2\cdot 3=58.$$

وبما أن \(0<\beta^3+\gamma^3<1\)، نحصل على

$$\left\lfloor a_2^3\right\rfloor=S_3-1=57.$$

نسخة C++ تستخدم هذا النوع من الحالات الصغيرة كفحوص تحقق قبل الاعتماد على المسار السريع الكامل.

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

الإصدارات الثلاثة تستخدم البنية نفسها. أولًا تحسب الدالة powMod القيمة \(c=2^n\bmod 10^8\). بعد ذلك ترفع الدالتان multiplyMatrix وpowerMatrix مصفوفة الانتقال \(3\times 3\) إلى القوة \(m-2\). وترجع الدالة computeNewtonSumMod القيمة \(S_m\bmod 10^8\)، مع معالجة الحالات \(m=0,1,2\) مباشرة، واستعمال أس المصفوفة لبقية الحالات.

ثم تطبق computeTermMod الهوية \(\lfloor a_n^m\rfloor\equiv S_m-1\pmod{10^8}\)، وتقوم solve بجمع القيم من \(n=1\) إلى \(30\). الملف الأطول في C++ يحتوي أيضًا على فحوص تحقق: مثال المسألة \(\lfloor a_2^2\rfloor=14\)، مقارنة بين العلاقة العودية بالمصفوفة والنسخة التكرارية، فحص عددي لهوية الأرضية في أمثلة صغيرة، واختبار اتساق التنفيذ أحادي الخيط ومتعدد الخيوط. لكن المسار النهائي نفسه يعتمد فقط على حسابات صحيحة.

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

لكل قيمة ثابتة من \(n\)، فإن الكلفة المهيمنة هي رفع مصفوفة \(3\times 3\) إلى القوة \(m-2\)، وهذا يحتاج إلى \(O(\log m)\) عملية ضرب مصفوفات. وبما أن عدد قيم \(n\) يساوي 30 فقط، فالتعقيد الكلي هو

$$O(30\log m)=O(\log m),$$

مع ذاكرة إضافية \(O(1)\). نسخة C++ يمكنها توزيع قيم \(n\) المستقلة على عدة خيوط، لكن هذا يحسن زمن التنفيذ العملي فقط.

مراجع

  1. صفحة المسألة: https://projecteuler.net/problem=356
  2. صيغ فييتا: Wikipedia - Vieta's formulas
  3. متطابقات نيوتن ومجاميع القوى: Wikipedia - Newton's identities
  4. أس المصفوفات للمتتاليات الخطية: cp-algorithms - binary exponentiation of recurrence transitions