The goal is to evaluate
$$S(n)=\sum_{k=1}^{n}\sum_{p=1}^{n}(1-k^2)^p \pmod{M},\qquad M=10^9+7.$$
For the actual input \(n=10^6\), a direct double loop would require about \(10^{12}\) term updates, so the computation must be reorganized. The key observation is that for each fixed \(k\), the inner sum is a finite geometric series. Once that series is collapsed to a closed form, the problem becomes a single loop over \(k\), with every contribution evaluated by modular exponentiation.
A useful checkpoint is
$$S(4)=51160,$$
which the implementation uses to confirm that the closed form matches direct evaluation on a small case.
The entire method comes from simplifying the inner sum for one fixed value of \(k\).
Define
$$u_k=1-k^2.$$
Then the contribution of this \(k\) to the outer sum is
$$T_k=\sum_{p=1}^{n}u_k^p.$$
Therefore
$$S(n)=\sum_{k=1}^{n}T_k.$$
This separates the problem into \(n\) independent geometric sums.
For \(u_k\neq 1\), the usual finite geometric-series identity gives
$$T_k=\frac{u_k^{n+1}-u_k}{u_k-1}=u_k\cdot\frac{u_k^n-1}{u_k-1}.$$
This is exactly the form used by the implementation: one fast power computes \(u_k^n\), and the remaining work is a small number of modular multiplications.
Because \(u_k=1-k^2\), we have
$$u_k-1=-k^2.$$
So the same quantity can also be written as
$$T_k=\frac{u_k-u_k^{n+1}}{k^2}.$$
This makes the arithmetic easier to interpret: the denominator is just \(k^2\). Under the Euler modulus \(M=10^9+7\), every \(k\) in the range \(1\le k\le 10^6\) is nonzero modulo \(M\), so the denominator is invertible for the actual problem input.
All calculations are performed modulo the prime \(M\). For any nonzero residue \(a\), Fermat's little theorem gives
$$a^{-1}\equiv a^{M-2}\pmod{M}.$$
Hence, for \(u_k\not\equiv 1\pmod{M}\),
$$T_k\equiv u_k\,(u_k^n-1)\,(u_k-1)^{-1}\pmod{M}.$$
This turns the whole computation into repeated modular exponentiation and multiplication, which is far cheaper than summing \(n\) powers for each \(k\).
If \(u_k\equiv 1\pmod{M}\), then every term in the inner sum equals \(1\), so
$$T_k\equiv n\pmod{M}.$$
For the actual Project Euler parameters this case does not occur, because \(u_k\equiv 1\) would imply \(k^2\equiv 0\pmod{M}\), impossible for \(1\le k<M\). Still, the implementation keeps this branch so the formula never attempts to divide by zero modulo \(M\).
Now compute the checkpoint directly.
For \(k=1\), \(u_1=1-1^2=0\), so
$$T_1=0+0+0+0=0.$$
For \(k=2\), \(u_2=-3\), hence
$$T_2=(-3)+(-3)^2+(-3)^3+(-3)^4=-3+9-27+81=60.$$
For \(k=3\), \(u_3=-8\), so
$$T_3=-8+64-512+4096=3640.$$
For \(k=4\), \(u_4=-15\), therefore
$$T_4=-15+225-3375+50625=47460.$$
Adding the four contributions gives
$$S(4)=0+60+3640+47460=51160,$$
which matches the checkpoint used by the implementation.
The C++, Python, and Java implementations all follow the same mathematical structure. They iterate once over \(k=1,2,\dots,n\), reduce \(1-k^2\) into the range \(0\) to \(M-1\), and then evaluate the closed form for \(T_k\) modulo \(M\).
For each \(k\), the implementation computes the power \(u_k^n \bmod M\) with binary exponentiation. If the denominator is nonzero, it computes the modular inverse by raising that denominator to the power \(M-2\), again with binary exponentiation. The resulting contribution is added to the running total modulo \(M\).
One implementation also includes two small validation steps: the known checkpoint \(S(4)=51160\), and a comparison between the optimized formula and direct summation for a small input. Those checks confirm that the algebraic reduction is correct before the large target value is evaluated.
There is one outer loop over \(k=1\) to \(n\). For each \(k\), the implementation performs a constant amount of arithmetic plus modular exponentiation for \(u_k^n\), and modular exponentiation for the inverse. Binary exponentiation costs \(O(\log n)\) for the first power and \(O(\log M)\) for the inverse, so the full running time is
$$O\bigl(n(\log n+\log M)\bigr).$$
With the fixed Euler modulus \(M=10^9+7\), this is effectively \(O(n\log n)\). The memory usage is
$$O(1),$$
since the program stores only a handful of current residues. This is a major improvement over the naive \(O(n^2)\) direct summation.
Gesucht ist der Wert
$$S(n)=\sum_{k=1}^{n}\sum_{p=1}^{n}(1-k^2)^p \pmod{M},\qquad M=10^9+7.$$
Für den eigentlichen Eingabewert \(n=10^6\) wäre eine direkte doppelte Schleife viel zu langsam, denn sie würde etwa \(10^{12}\) Einzelterme auswerten. Die Lösung nutzt deshalb die Tatsache, dass die innere Summe für festes \(k\) eine endliche geometrische Reihe ist. Dadurch wird aus dem quadratischen Verfahren eine einfache Schleife über \(k\), in der jeder Beitrag mit modularer Potenzierung berechnet wird.
Ein wichtiger Kontrollwert ist
$$S(4)=51160,$$
und genau dieser Wert wird verwendet, um die geschlossene Formel an einem kleinen Beispiel zu überprüfen.
Der gesamte Trick besteht darin, die innere Summe für ein festes \(k\) algebraisch zusammenzufassen.
Definiere
$$u_k=1-k^2.$$
Dann ist der Beitrag dieses \(k\) zur Gesamtsumme
$$T_k=\sum_{p=1}^{n}u_k^p.$$
Somit gilt
$$S(n)=\sum_{k=1}^{n}T_k.$$
Das Problem zerfällt also in \(n\) voneinander unabhängige geometrische Reihen.
Für \(u_k\neq 1\) liefert die bekannte Formel für endliche geometrische Reihen
$$T_k=\frac{u_k^{n+1}-u_k}{u_k-1}=u_k\cdot\frac{u_k^n-1}{u_k-1}.$$
Genau diese Form wird in der Implementierung ausgewertet: Eine schnelle Potenz liefert \(u_k^n\), der Rest sind nur noch wenige modulare Multiplikationen.
Aus \(u_k=1-k^2\) folgt unmittelbar
$$u_k-1=-k^2.$$
Damit kann derselbe Ausdruck auch geschrieben werden als
$$T_k=\frac{u_k-u_k^{n+1}}{k^2}.$$
So sieht man klar, dass im Nenner nur \(k^2\) steht. Unter dem Euler-Modulus \(M=10^9+7\) ist für alle \(1\le k\le 10^6\) dieser Nenner invertierbar, denn kein solches \(k\) ist modulo \(M\) gleich null.
Da \(M\) prim ist, gilt für jede von null verschiedene Restklasse \(a\)
$$a^{-1}\equiv a^{M-2}\pmod{M}.$$
Also erhält man für \(u_k\not\equiv 1\pmod{M}\)
$$T_k\equiv u_k\,(u_k^n-1)\,(u_k-1)^{-1}\pmod{M}.$$
Damit besteht die gesamte Berechnung nur noch aus modularer Potenzierung und modularer Multiplikation, statt aus \(n\) einzelnen Potenzen pro \(k\).
Falls \(u_k\equiv 1\pmod{M}\), ist jeder Summand der inneren Summe gleich \(1\), also
$$T_k\equiv n\pmod{M}.$$
Für die echten Problemparameter tritt dieser Fall nicht ein, denn \(u_k\equiv 1\) würde \(k^2\equiv 0\pmod{M}\) bedeuten, was für \(1\le k<M\) unmöglich ist. Die Implementierung behält diesen Zweig trotzdem bei, damit niemals durch null modulo \(M\) dividiert wird.
Nun berechnen wir den Kontrollwert direkt.
Für \(k=1\) ist \(u_1=0\), also
$$T_1=0+0+0+0=0.$$
Für \(k=2\) gilt \(u_2=-3\), damit
$$T_2=(-3)+(-3)^2+(-3)^3+(-3)^4=-3+9-27+81=60.$$
Für \(k=3\) ist \(u_3=-8\), also
$$T_3=-8+64-512+4096=3640.$$
Für \(k=4\) erhält man \(u_4=-15\) und damit
$$T_4=-15+225-3375+50625=47460.$$
Die Summe aller Beiträge ist
$$S(4)=0+60+3640+47460=51160,$$
genau der Kontrollwert der Implementierung.
Die C++-, Python- und Java-Implementierungen folgen alle derselben mathematischen Struktur. Sie durchlaufen einmal \(k=1,2,\dots,n\), bringen \(1-k^2\) zunächst in den Restklassenbereich \(0\) bis \(M-1\) und berechnen danach den geschlossenen Ausdruck für \(T_k\) modulo \(M\).
Für jedes \(k\) wird \(u_k^n \bmod M\) mit binärer Potenzierung berechnet. Ist der Nenner ungleich null, wird sein modulares Inverses über die Potenz \(M-2\) bestimmt, wiederum mit binärer Potenzierung. Anschließend wird der Beitrag zu einer laufenden Summe modulo \(M\) addiert.
Eine der Implementierungen enthält zusätzlich zwei kleine Prüfungen: den bekannten Wert \(S(4)=51160\) sowie einen Vergleich zwischen geschlossener Formel und direkter Auswertung für eine kleine Eingabe. Dadurch wird bestätigt, dass die algebraische Umformung korrekt implementiert ist.
Es gibt genau eine äußere Schleife über \(k=1\) bis \(n\). Für jedes \(k\) fallen nur konstant viele modulare Multiplikationen sowie eine Potenzierung für \(u_k^n\) und eine Potenzierung für das Inverse an. Mit binärer Potenzierung ergibt das
$$O\bigl(n(\log n+\log M)\bigr)$$
Zeit. Da \(M=10^9+7\) fest ist, kann man dies praktisch als
$$O(n\log n)$$
auffassen. Der Speicherbedarf ist
$$O(1),$$
weil nur wenige aktuelle Restklassen gehalten werden. Gegenüber der naiven \(O(n^2)\)-Methode ist das ein entscheidender Gewinn.
Hedef,
$$S(n)=\sum_{k=1}^{n}\sum_{p=1}^{n}(1-k^2)^p \pmod{M},\qquad M=10^9+7$$
değerini hesaplamaktır. Gerçek girdi \(n=10^6\) olduğundan, doğrudan çift döngüyle ilerlemek yaklaşık \(10^{12}\) terim üretir ve pratik değildir. Çözümün temel gözlemi, sabit bir \(k\) için iç toplamın sonlu bir geometrik seri olmasıdır. Bu seri kapalı forma indirildiğinde problem, her katkının modüler üs alma ile bulunduğu tek bir dış döngüye dönüşür.
Önemli bir kontrol değeri şudur:
$$S(4)=51160.$$
Uygulama, küçük bir örnekte kapalı formun doğru çalıştığını bu değerle doğrular.
Bütün yöntem, tek bir \(k\) değeri için iç toplamı sadeleştirmeye dayanır.
Şunu tanımlayalım:
$$u_k=1-k^2.$$
Bu durumda ilgili \(k\)'nin dış toplama katkısı
$$T_k=\sum_{p=1}^{n}u_k^p$$
olur. Dolayısıyla
$$S(n)=\sum_{k=1}^{n}T_k$$
yazabiliriz. Böylece problem \(n\) bağımsız geometrik seri hesabına ayrılır.
\(u_k\neq 1\) için sonlu geometrik seri formülü
$$T_k=\frac{u_k^{n+1}-u_k}{u_k-1}=u_k\cdot\frac{u_k^n-1}{u_k-1}$$
sonucunu verir. Uygulama tam olarak bu ifadeyi kullanır: önce \(u_k^n\) hızlı üs alma ile bulunur, sonra birkaç modüler çarpma yapılır.
\(u_k=1-k^2\) olduğundan
$$u_k-1=-k^2$$
elde edilir. Aynı ifade bu yüzden
$$T_k=\frac{u_k-u_k^{n+1}}{k^2}$$
şeklinde de yazılabilir. Bu görünüm, paydanın yalnızca \(k^2\) olduğunu açıkça gösterir. Euler modülü \(M=10^9+7\) altında ve \(1\le k\le 10^6\) aralığında, hiçbir \(k\) mod \(M\)'de sıfır olmadığı için bu payda terslenebilir.
\(M\) asal olduğundan, sıfır olmayan her \(a\) için
$$a^{-1}\equiv a^{M-2}\pmod{M}$$
vardır. Bu nedenle \(u_k\not\equiv1\pmod{M}\) iken
$$T_k\equiv u_k\,(u_k^n-1)\,(u_k-1)^{-1}\pmod{M}$$
yazılır. Böylece her \(k\) için \(n\) tane kuvvet toplamak yerine yalnızca modüler üs alma ve çarpma yapmak yeterli olur.
Eğer \(u_k\equiv1\pmod{M}\) ise iç toplamın her terimi \(1\) olur ve
$$T_k\equiv n\pmod{M}$$
elde edilir. Gerçek Euler girdisinde bu durum yaşanmaz; çünkü \(u_k\equiv1\) olması \(k^2\equiv0\pmod{M}\) anlamına gelir ve \(1\le k<M\) iken bu imkansızdır. Yine de uygulama, modüler olarak sıfıra bölme ihtimalini tamamen ortadan kaldırmak için bu dalı korur.
Şimdi kontrol değerini doğrudan hesaplayalım.
\(k=1\) için \(u_1=0\), dolayısıyla
$$T_1=0+0+0+0=0.$$
\(k=2\) için \(u_2=-3\), o halde
$$T_2=(-3)+(-3)^2+(-3)^3+(-3)^4=-3+9-27+81=60.$$
\(k=3\) için \(u_3=-8\), bu da
$$T_3=-8+64-512+4096=3640$$
verir. \(k=4\) için \(u_4=-15\) olduğundan
$$T_4=-15+225-3375+50625=47460.$$
Toplayınca
$$S(4)=0+60+3640+47460=51160$$
elde edilir; bu da uygulamanın kullandığı kontrol değeriyle aynıdır.
C++, Python ve Java uygulamaları aynı matematiksel planı izler. Önce \(k=1,2,\dots,n\) üzerinde tek bir döngü kurulur. Her adımda \(1-k^2\) ifadesi mod \(M\) altında \(0\) ile \(M-1\) arasına taşınır ve ardından \(T_k\) için elde edilen kapalı form değerlendirilir.
Her \(k\) için \(u_k^n \bmod M\) değeri ikili üs alma ile hesaplanır. Payda sıfır değilse modüler tersi yine ikili üs alma ile, bu kez üs \(M-2\) kullanılarak bulunur. Son katkı çarpılıp toplam cevaba mod \(M\) altında eklenir.
Bir uygulama ayrıca iki küçük doğrulama içerir: \(S(4)=51160\) kontrolü ve küçük bir girişte kapalı formun doğrudan toplamla karşılaştırılması. Böylece cebirsel dönüşümün doğru uygulandığı teyit edilir.
Dışarıda yalnızca \(k=1\) ile \(n\) arasında tek bir döngü vardır. Her \(k\) için sabit sayıda modüler işlem, bir adet \(u_k^n\) hesabı ve bir adet modüler ters hesabı yapılır. İkili üs alma kullanıldığında toplam süre
$$O\bigl(n(\log n+\log M)\bigr)$$
olur. Sabit Euler modülü \(M=10^9+7\) için bu pratikte
$$O(n\log n)$$
olarak görülebilir. Bellek kullanımı
$$O(1)$$
seviyesindedir; çünkü yalnızca birkaç geçici modüler değer saklanır. Bu, doğrudan \(O(n^2)\) yönteme göre çok büyük bir iyileşmedir.
Se quiere calcular
$$S(n)=\sum_{k=1}^{n}\sum_{p=1}^{n}(1-k^2)^p \pmod{M},\qquad M=10^9+7.$$
Para el valor real \(n=10^6\), una evaluación directa con dos bucles sería inviable, porque implicaría alrededor de \(10^{12}\) actualizaciones de términos. La observación decisiva es que, para cada \(k\) fijo, la suma interior es una serie geométrica finita. Al reemplazar esa serie por una fórmula cerrada, todo el problema se reduce a un único recorrido sobre \(k\), donde cada contribución se obtiene mediante potenciación modular.
Un punto de control muy útil es
$$S(4)=51160,$$
que permite verificar en un caso pequeño que la fórmula cerrada coincide con la suma directa.
Todo el método nace de simplificar la suma interior para un valor fijo de \(k\).
Definimos
$$u_k=1-k^2.$$
Entonces la contribución correspondiente a ese \(k\) es
$$T_k=\sum_{p=1}^{n}u_k^p.$$
Por tanto,
$$S(n)=\sum_{k=1}^{n}T_k.$$
Así el problema queda dividido en \(n\) series geométricas independientes.
Si \(u_k\neq 1\), la identidad usual para una serie geométrica finita da
$$T_k=\frac{u_k^{n+1}-u_k}{u_k-1}=u_k\cdot\frac{u_k^n-1}{u_k-1}.$$
Ésta es exactamente la forma que usan las implementaciones: una potenciación rápida produce \(u_k^n\) y el resto son unas pocas multiplicaciones modulares.
Como \(u_k=1-k^2\), se tiene
$$u_k-1=-k^2.$$
Por eso la misma expresión también puede escribirse como
$$T_k=\frac{u_k-u_k^{n+1}}{k^2}.$$
Esta forma deja claro que el denominador es simplemente \(k^2\). Bajo el módulo primo \(M=10^9+7\), todo \(k\) del rango real \(1\le k\le 10^6\) es no nulo módulo \(M\), de modo que el inverso existe.
Como \(M\) es primo, para cualquier residuo no nulo \(a\) vale
$$a^{-1}\equiv a^{M-2}\pmod{M}.$$
En consecuencia, cuando \(u_k\not\equiv 1\pmod{M}\),
$$T_k\equiv u_k\,(u_k^n-1)\,(u_k-1)^{-1}\pmod{M}.$$
Esto reemplaza una suma de \(n\) potencias por una pequeña cantidad de exponenciaciones y multiplicaciones modulares.
Si \(u_k\equiv 1\pmod{M}\), entonces todos los términos de la suma interior valen \(1\), y por tanto
$$T_k\equiv n\pmod{M}.$$
Para los parámetros reales del problema ese caso no aparece, porque \(u_k\equiv 1\) implicaría \(k^2\equiv 0\pmod{M}\), imposible cuando \(1\le k<M\). Aun así, la implementación conserva esta rama para evitar cualquier división por cero modular.
Calculemos ahora el valor de control.
Para \(k=1\), \(u_1=0\), luego
$$T_1=0+0+0+0=0.$$
Para \(k=2\), \(u_2=-3\), así que
$$T_2=(-3)+(-3)^2+(-3)^3+(-3)^4=-3+9-27+81=60.$$
Para \(k=3\), \(u_3=-8\), por lo que
$$T_3=-8+64-512+4096=3640.$$
Para \(k=4\), \(u_4=-15\), y entonces
$$T_4=-15+225-3375+50625=47460.$$
Sumando todas las contribuciones se obtiene
$$S(4)=0+60+3640+47460=51160,$$
exactamente el valor de control usado por la implementación.
Las implementaciones en C++, Python y Java siguen la misma estructura matemática. Recorren una sola vez \(k=1,2,\dots,n\), reducen \(1-k^2\) al intervalo \(0\) a \(M-1\), y después evalúan la fórmula cerrada de \(T_k\) módulo \(M\).
Para cada \(k\), la implementación calcula \(u_k^n \bmod M\) mediante exponenciación binaria. Si el denominador no es cero, obtiene el inverso modular elevándolo a la potencia \(M-2\), otra vez con exponenciación binaria. Luego añade la contribución resultante al acumulado total módulo \(M\).
Una de las implementaciones también incluye dos comprobaciones pequeñas: el valor conocido \(S(4)=51160\) y una comparación entre la fórmula optimizada y la suma directa para una entrada reducida. Eso confirma que la transformación algebraica se programó correctamente.
Existe un único bucle exterior sobre \(k=1\) hasta \(n\). Para cada \(k\) se hacen unas pocas operaciones modulares, una potenciación para \(u_k^n\) y otra para el inverso. Con exponenciación binaria, el coste total es
$$O\bigl(n(\log n+\log M)\bigr).$$
Como \(M=10^9+7\) es fijo, esto equivale en la práctica a
$$O(n\log n).$$
La memoria utilizada es
$$O(1),$$
ya que sólo se mantienen unas pocas cantidades modulares corrientes. Es una mejora muy grande frente al enfoque directo de orden \(O(n^2)\).
目标是计算
$$S(n)=\sum_{k=1}^{n}\sum_{p=1}^{n}(1-k^2)^p \pmod{M},\qquad M=10^9+7$$
当真实输入为 \(n=10^6\) 时,直接按照定义做双重循环需要大约 \(10^{12}\) 次项更新,显然不可行。解法的关键观察是:对每个固定的 \(k\),内层求和都是一个有限等比级数。只要把这段等比级数改写成闭式,整个问题就从 \(O(n^2)\) 的直接求和,转化为只对 \(k\) 做一次扫描,并在每一步用模幂计算当前贡献。
实现里还使用了一个很重要的校验值:
$$S(4)=51160$$
这个小样例可以用来确认闭式公式与直接求和完全一致。
整个方法都来自于对固定 \(k\) 时内层和式的代数化简。
定义
$$u_k=1-k^2$$
那么这个 \(k\) 对总和的贡献就是
$$T_k=\sum_{p=1}^{n}u_k^p$$
于是总和可以写成
$$S(n)=\sum_{k=1}^{n}T_k$$
这样一来,原问题就被拆成了 \(n\) 个彼此独立的等比级数。
当 \(u_k\neq 1\) 时,有限等比级数公式给出
$$T_k=\frac{u_k^{n+1}-u_k}{u_k-1}=u_k\cdot\frac{u_k^n-1}{u_k-1}$$
实现正是按这个形式来计算的:先用快速幂求出 \(u_k^n\),然后再做少量模乘即可得到当前项。
因为 \(u_k=1-k^2\),所以
$$u_k-1=-k^2$$
因此同一个表达式也可以改写成
$$T_k=\frac{u_k-u_k^{n+1}}{k^2}$$
这个写法更容易解释代码里的除法步骤,因为分母其实只是 \(k^2\)。在题目指定的模数 \(M=10^9+7\) 下,真实输入满足 \(1\le k\le 10^6<M\),所以 \(k\) 不可能在模 \(M\) 意义下等于零,分母自然总是可逆的。
由于 \(M\) 是素数,对任意非零剩余类 \(a\) 都有
$$a^{-1}\equiv a^{M-2}\pmod{M}$$
因此,只要 \(u_k\not\equiv 1\pmod{M}\),就可以写成
$$T_k\equiv u_k\,(u_k^n-1)\,(u_k-1)^{-1}\pmod{M}$$
这一步把“对每个 \(k\) 再求一遍长度为 \(n\) 的幂和”变成了“做几次模幂和模乘”,计算量立刻下降了几个数量级。
如果 \(u_k\equiv 1\pmod{M}\),那么内层每一项都等于 \(1\),于是
$$T_k\equiv n\pmod{M}$$
对于本题真实参数,这种情况其实不会出现,因为 \(u_k\equiv 1\) 等价于 \(k^2\equiv 0\pmod{M}\),而 \(1\le k<M\) 时这是不可能的。不过实现仍然保留这一分支,从而在更一般的情形下也不会发生模意义下的零除。
下面直接算出校验值。
当 \(k=1\) 时,\(u_1=0\),所以
$$T_1=0+0+0+0=0$$
当 \(k=2\) 时,\(u_2=-3\),因此
$$T_2=(-3)+(-3)^2+(-3)^3+(-3)^4=-3+9-27+81=60$$
当 \(k=3\) 时,\(u_3=-8\),于是
$$T_3=-8+64-512+4096=3640$$
当 \(k=4\) 时,\(u_4=-15\),所以
$$T_4=-15+225-3375+50625=47460$$
把四项相加得到
$$S(4)=0+60+3640+47460=51160$$
这正好与实现中的检查结果一致。
C++、Python 和 Java 实现遵循完全相同的数学流程。它们只保留一层对 \(k=1,2,\dots,n\) 的循环;在每次循环中,先把 \(1-k^2\) 归约到 \(0\) 到 \(M-1\) 的标准模表示,再根据上面的闭式公式求出当前 \(T_k\) 的贡献。
对每个 \(k\),实现首先用二进制快速幂求出 \(u_k^n \bmod M\)。如果分母非零,再通过把分母提升到 \(M-2\) 次方来得到模逆,这一步同样使用快速幂。随后把当前贡献加到答案中,并在每一步都取模。
其中一个实现还包含两道小规模验证:一是检查 \(S(4)=51160\),二是在较小输入上把优化公式与直接求和结果逐项对比。这样就能确认代码确实实现了同一个数学公式,而不是只在大输入上“看起来合理”。
外层只有一重循环,共执行 \(n\) 次。每个 \(k\) 需要常数次模运算、一次求 \(u_k^n\) 的快速幂、以及一次求模逆的快速幂。因此总时间复杂度是
$$O\bigl(n(\log n+\log M)\bigr)$$
由于题目里的模数固定为 \(M=10^9+7\),实际可以把它看成
$$O(n\log n)$$
空间复杂度为
$$O(1)$$
因为程序只保存少量当前模值,不需要任何与 \(n\) 成比例的额外数组。这比直接做双重求和的 \(O(n^2)\) 方法高效得多。
Требуется вычислить
$$S(n)=\sum_{k=1}^{n}\sum_{p=1}^{n}(1-k^2)^p \pmod{M},\qquad M=10^9+7.$$
При реальном значении \(n=10^6\) прямой двойной цикл был бы слишком дорогим, потому что пришлось бы обработать около \(10^{12}\) слагаемых. Ключевое наблюдение состоит в том, что при фиксированном \(k\) внутренняя сумма является конечной геометрической прогрессией. После сведения этой прогрессии к замкнутой формуле задача превращается в один проход по \(k\), а каждый вклад вычисляется с помощью модульного возведения в степень.
Важная контрольная точка:
$$S(4)=51160,$$
и именно этот результат используется для проверки формулы на малом примере.
Весь метод строится на алгебраическом упрощении внутренней суммы для одного фиксированного \(k\).
Обозначим
$$u_k=1-k^2.$$
Тогда вклад данного \(k\) во внешнюю сумму равен
$$T_k=\sum_{p=1}^{n}u_k^p.$$
Следовательно,
$$S(n)=\sum_{k=1}^{n}T_k.$$
То есть исходная задача распадается на \(n\) независимых геометрических сумм.
Если \(u_k\neq 1\), стандартная формула для конечной геометрической прогрессии даёт
$$T_k=\frac{u_k^{n+1}-u_k}{u_k-1}=u_k\cdot\frac{u_k^n-1}{u_k-1}.$$
Именно в таком виде выражение вычисляется в реализации: одно быстрое возведение в степень даёт \(u_k^n\), после чего остаётся несколько модульных умножений.
Так как \(u_k=1-k^2\), имеем
$$u_k-1=-k^2.$$
Поэтому тот же вклад можно записать и так:
$$T_k=\frac{u_k-u_k^{n+1}}{k^2}.$$
Эта форма особенно наглядна: знаменатель равен просто \(k^2\). При модуле задачи \(M=10^9+7\) и диапазоне \(1\le k\le 10^6\) никакое такое \(k\) не равно нулю по модулю \(M\), значит знаменатель всегда обратим.
Поскольку \(M\) простое, для любого ненулевого остатка \(a\) выполняется
$$a^{-1}\equiv a^{M-2}\pmod{M}.$$
Значит, при \(u_k\not\equiv 1\pmod{M}\) можно вычислять
$$T_k\equiv u_k\,(u_k^n-1)\,(u_k-1)^{-1}\pmod{M}.$$
Тем самым внутренняя сумма длины \(n\) заменяется двумя быстрыми степенями и несколькими модульными операциями.
Если \(u_k\equiv 1\pmod{M}\), то каждое слагаемое внутренней суммы равно \(1\), и поэтому
$$T_k\equiv n\pmod{M}.$$
Для реальных параметров Euler этот случай не возникает, потому что \(u_k\equiv 1\) означало бы \(k^2\equiv 0\pmod{M}\), а это невозможно при \(1\le k<M\). Тем не менее реализация сохраняет отдельную ветку, чтобы никогда не делить на ноль по модулю.
Вычислим контрольное значение напрямую.
Для \(k=1\) имеем \(u_1=0\), значит
$$T_1=0+0+0+0=0.$$
Для \(k=2\) получаем \(u_2=-3\), следовательно
$$T_2=(-3)+(-3)^2+(-3)^3+(-3)^4=-3+9-27+81=60.$$
Для \(k=3\) имеем \(u_3=-8\), откуда
$$T_3=-8+64-512+4096=3640.$$
Для \(k=4\) выходит \(u_4=-15\), поэтому
$$T_4=-15+225-3375+50625=47460.$$
Сумма всех вкладов равна
$$S(4)=0+60+3640+47460=51160,$$
что точно совпадает с контрольным значением из реализации.
Реализации на C++, Python и Java используют одну и ту же математическую схему. Они выполняют единственный проход по \(k=1,2,\dots,n\), приводят выражение \(1-k^2\) к стандартному остатку от \(0\) до \(M-1\), а затем вычисляют вклад \(T_k\) по замкнутой формуле.
Для каждого \(k\) программа сначала находит \(u_k^n \bmod M\) методом бинарного возведения в степень. Если знаменатель не равен нулю, затем вычисляется модульный обратный как степень \(M-2\), опять же бинарным методом. После этого текущий вклад прибавляется к накопленному ответу по модулю \(M\).
Одна из реализаций дополнительно содержит две маленькие проверки: значение \(S(4)=51160\) и сравнение оптимизированной формулы с прямым суммированием на небольшом входе. Это подтверждает корректность алгебраического преобразования.
Есть ровно один внешний цикл по \(k\) от \(1\) до \(n\). Для каждого \(k\) выполняется постоянное число модульных операций, одно быстрое возведение в степень для \(u_k^n\) и ещё одно для вычисления обратного элемента. Поэтому полное время работы равно
$$O\bigl(n(\log n+\log M)\bigr).$$
Так как в задаче модуль фиксирован и равен \(M=10^9+7\), это практически эквивалентно
$$O(n\log n).$$
Память требуется лишь
$$O(1),$$
поскольку хранятся только несколько текущих остатков. Это гораздо лучше прямого подхода порядка \(O(n^2)\).
المطلوب هو حساب
$$S(n)=\sum_{k=1}^{n}\sum_{p=1}^{n}(1-k^2)^p \pmod{M},\qquad M=10^9+7.$$
عندما يكون الإدخال الحقيقي \(n=10^6\)، فإن التنفيذ المباشر بحلقتين متداخلتين يحتاج تقريبًا إلى \(10^{12}\) تحديثًا، وهذا غير عملي. الفكرة الأساسية هي أن المجموع الداخلي، عند تثبيت \(k\)، عبارة عن متتالية هندسية منتهية. وبعد تحويل هذا المجموع إلى صيغة مغلقة، تصبح المسألة مجرد حلقة واحدة على \(k\)، مع حساب كل مساهمة باستعمال الأسّ المعياري السريع.
هناك قيمة تحقق مهمة هي
$$S(4)=51160,$$
وتُستخدم للتأكد من أن الصيغة المغلقة تطابق الجمع المباشر في حالة صغيرة.
تعتمد الطريقة كلها على تبسيط المجموع الداخلي لقيمة ثابتة من \(k\).
لنعرّف
$$u_k=1-k^2.$$
عندئذ تصبح مساهمة هذا \(k\) في المجموع الخارجي
$$T_k=\sum_{p=1}^{n}u_k^p.$$
وبالتالي
$$S(n)=\sum_{k=1}^{n}T_k.$$
أي أن المسألة الأصلية تنقسم إلى \(n\) مجاميع هندسية مستقلة.
إذا كان \(u_k\neq 1\)، فإن صيغة المجموع الهندسي المنتهي تعطي
$$T_k=\frac{u_k^{n+1}-u_k}{u_k-1}=u_k\cdot\frac{u_k^n-1}{u_k-1}.$$
وهذه هي الصيغة نفسها التي تعتمدها التطبيقات: نحسب أولًا \(u_k^n\) بالأسّ السريع، ثم نُكمل بعدد قليل من الضربات المعيارية.
بما أن \(u_k=1-k^2\)، فإن
$$u_k-1=-k^2.$$
ولهذا يمكن أيضًا كتابة المقدار نفسه على الصورة
$$T_k=\frac{u_k-u_k^{n+1}}{k^2}.$$
هذه الصيغة توضح أن المقام ليس إلا \(k^2\). ومع المودولو الأولي \(M=10^9+7\)، وكل \(k\) في المجال الحقيقي \(1\le k\le 10^6\)، لا يمكن أن يكون \(k\equiv0\pmod{M}\)، لذلك يكون المقام قابلاً للعكس دائمًا في الإدخال الفعلي.
لأن \(M\) عدد أولي، فإن كل باقي غير صفري \(a\) يحقق
$$a^{-1}\equiv a^{M-2}\pmod{M}.$$
ومن ثم، عندما \(u_k\not\equiv1\pmod{M}\)، نحصل على
$$T_k\equiv u_k\,(u_k^n-1)\,(u_k-1)^{-1}\pmod{M}.$$
وبذلك نتحول من جمع \(n\) حدود لكل \(k\) إلى عدد صغير من عمليات الأسّ المعياري والضرب المعياري.
إذا تحقق \(u_k\equiv1\pmod{M}\)، فإن كل حد في المجموع الداخلي يساوي \(1\)، وبالتالي
$$T_k\equiv n\pmod{M}.$$
هذه الحالة لا تظهر في معطيات المسألة الفعلية، لأن \(u_k\equiv1\) يعني \(k^2\equiv0\pmod{M}\)، وهذا مستحيل عندما \(1\le k<M\). ومع ذلك تحتفظ التطبيقات بهذا الفرع كي لا يحدث أي تقسيم على الصفر في الحسابات المعيارية.
لنحسب الآن قيمة التحقق مباشرة.
عند \(k=1\) نجد \(u_1=0\)، ومن ثم
$$T_1=0+0+0+0=0.$$
وعند \(k=2\) يكون \(u_2=-3\)، لذا
$$T_2=(-3)+(-3)^2+(-3)^3+(-3)^4=-3+9-27+81=60.$$
وعند \(k=3\) نحصل على \(u_3=-8\)، وبالتالي
$$T_3=-8+64-512+4096=3640.$$
وعند \(k=4\) يكون \(u_4=-15\)، فينتج
$$T_4=-15+225-3375+50625=47460.$$
وبجمع هذه المساهمات كلها نحصل على
$$S(4)=0+60+3640+47460=51160,$$
وهو تمامًا مقدار التحقق الموجود في التنفيذ.
تتبع تطبيقات C++ وPython وJava البنية الرياضية نفسها. فهي تمر مرة واحدة على \(k=1,2,\dots,n\)، ثم تحوّل المقدار \(1-k^2\) إلى باقي معياري بين \(0\) و\(M-1\)، وبعد ذلك تحسب مساهمة \(T_k\) من الصيغة المغلقة.
لكل \(k\)، تحسب الشيفرة أولًا \(u_k^n \bmod M\) باستخدام الأسّ الثنائي السريع. وإذا كان المقام غير صفري، تحسب معكوسه الضربي برفعه إلى القوة \(M-2\)، أيضًا بالأسّ السريع. بعد ذلك تُضاف المساهمة الحالية إلى الجواب الكلي مع أخذ المودولو في كل خطوة.
ويحتوي أحد التطبيقات كذلك على تحققين صغيرين: التأكد من أن \(S(4)=51160\)، ومقارنة الصيغة المحسّنة مع الجمع المباشر على إدخال صغير. وهذا يثبت أن الاختزال الجبري نُفِّذ بصورة صحيحة.
هناك حلقة خارجية واحدة فقط على \(k\) من \(1\) إلى \(n\). ولكل قيمة من \(k\)، تُنفَّذ كمية ثابتة من العمليات المعيارية، بالإضافة إلى أسّ سريع لحساب \(u_k^n\)، وأسّ سريع آخر لحساب المعكوس. لذلك يكون الزمن الكلي
$$O\bigl(n(\log n+\log M)\bigr).$$
ومع ثبات المودولو في المسألة عند \(M=10^9+7\)، يمكن النظر إلى ذلك عمليًا على أنه
$$O(n\log n).$$
أما الذاكرة فهي
$$O(1),$$
لأن البرنامج يحتفظ بعدد قليل فقط من القيم الحالية. وهذا أفضل بكثير من الطريقة المباشرة ذات الكلفة \(O(n^2)\).