Investigating Gaussian Integers
For 1 <= n <= N = 10^8, find sum_(n=1)^N R(n), where R(n) is the sum of the real parts of all Gaussian integer divisors of n that have positive real part. A Gaussian integer g = a + bi (with a, b i...
Problem Statement
This archive keeps the full statement, math, and original media on the page.
As we all know the equation $x^2=-1$ has no solutions for real $x$.
If we however introduce the imaginary number $i$ this equation has two solutions: $x=i$ and $x=-i$.
If we go a step further the equation $(x-3)^2=-4$ has two complex solutions: $x=3+2i$ and $x=3-2i$.
$x=3+2i$ and $x=3-2i$ are called each others' complex conjugate.
Numbers of the form $a+bi$ are called complex numbers.
In general $a+bi$ and $a-bi$ are each other's complex conjugate.
A Gaussian Integer is a complex number $a+bi$ such that both $a$ and $b$ are integers.
The regular integers are also Gaussian integers (with $b=0$).
To distinguish them from Gaussian integers with $b \ne 0$ we call such integers "rational integers."
A Gaussian integer $a+bi$ is called a divisor of a rational integer $n$ if the result $\dfrac n {a + bi}$ is also a Gaussian integer.
If for example we divide $5$ by $1+2i$ we can simplify $\dfrac{5}{1 + 2i}$ in the following manner:
Multiply numerator and denominator by the complex conjugate of $1+2i$: $1-2i$.
The result is $\dfrac{5}{1 + 2i} = \dfrac{5}{1 + 2i}\dfrac{1 - 2i}{1 - 2i} = \dfrac{5(1 - 2i)}{1 - (2i)^2} = \dfrac{5(1 - 2i)}{1 - (-4)} = \dfrac{5(1 - 2i)}{5} = 1 - 2i$.
So $1+2i$ is a divisor of $5$.
Note that $1+i$ is not a divisor of $5$ because $\dfrac{5}{1 + i} = \dfrac{5}{2} - \dfrac{5}{2}i$.
Note also that if the Gaussian Integer $(a+bi)$ is a divisor of a rational integer $n$, then its complex conjugate $(a-bi)$ is also a divisor of $n$.
In fact, $5$ has six divisors such that the real part is positive: $\{1, 1 + 2i, 1 - 2i, 2 + i, 2 - i, 5\}$.
The following is a table of all of the divisors for the first five positive rational integers:
| $\textcolor{red}{n}$ | Gaussian interger divisors with positive real part | Sum of these divisors |
| $1$ | $1$ | $1$ |
| $2$ | $1, 1 + i, 1 - i, 2$ | $5$ |
| $3$ | $1, 3$ | $4$ |
| $4$ | $1, 1 + i, 1 - i, 2, 2 + 2i, 2 - 2i, 4$ | $13$ |
| $5$ | $1, 1 + 2i, 1 - 2i, 2 + i, 2 - i, 5$ | $12$ |
For divisors with positive real parts, then, we have: $\displaystyle \sum \limits_{n = 1}^{5} {s(n)} = 35$.
You are also given $\displaystyle \sum \limits_{n = 1}^{10^5} {s(n)} = 17924657155$.
What is $\displaystyle \sum \limits_{n = 1}^{10^8} {s(n)}$?
Problem 153: Investigating Gaussian Integers
Mathematical Development
Definition 1. A Gaussian integer is an element of . The norm of is . For a positive integer , a Gaussian integer divides if .
Theorem 1 (Divisibility Criterion). Let with and , not both zero. Then in if and only if .
Proof. We have . This lies in if and only if and . Since , we claim (the last equality follows because any prime dividing both and divides , contradicting ). Similarly . Therefore both conditions reduce to .
Theorem 2 (General Divisibility). For a general Gaussian integer where , , , and , we have if and only if .
Proof. Write . For this to lie in , we need , i.e., , which requires and , i.e., .
Theorem 3 (Decomposition of ). Let denote the sum of the real parts of all Gaussian integer divisors of with positive real part. Then:
where is the standard divisor sum function.
Proof. The Gaussian divisors of with positive real part decompose into three classes:
- Real divisors with , : contribute .
- Purely imaginary divisors : contribute real part .
- Complex divisors with , : for each such divisor with , the conjugate also divides (since is real) and has the same positive real part . Writing , with , the pair contributes .
Summing over all coprime pairs with and all valid multipliers yields the formula.
Theorem 4 (Summation Formula). The total answer is:
Proof. For : by exchanging the order of summation.
For : fix a coprime pair and a multiplier . The Gaussian integer divides exactly those that are multiples of . Writing , the number of such is , and each contributes real part . Summing over all and exchanging with the sum over yields the formula.
Lemma 1 (Efficient Evaluation of ). The sum can be computed in time via the hyperbola method.
Proof. There are at most distinct values of for . Group consecutive values of sharing the same quotient into blocks where . Within each block, is computed in .
Editorial
We part 1: Divisor sum via hyperbola method. We then part 2: Gaussian integer contributions. Finally, sum over multiplier k using hyperbola method.
Pseudocode
Part 1: Divisor sum via hyperbola method
Part 2: Gaussian integer contributions
Sum over multiplier k using hyperbola method
Complexity Analysis
- Time: for via the hyperbola method. For , the outer loops iterate over coprime pairs with , totaling pairs (approximately coprime lattice points in the quarter-disk). The inner hyperbola summation for each pair takes , but the aggregate cost is dominated by . Total: .
- Space: auxiliary space.
Answer
Code
Each problem page includes the exact C++ and Python source files from the local archive.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
const ll N = 100000000LL;
// Part 1: sum_{d=1}^{N} d * floor(N/d) via hyperbola method
ll part1 = 0;
for (ll d = 1; d <= N; ) {
ll q = N / d;
ll d_max = N / q;
part1 += q * (d + d_max) * (d_max - d + 1) / 2;
d = d_max + 1;
}
// Part 2: Gaussian integer contributions
ll part2 = 0;
for (ll b = 1; b * b + 1 <= N; b++) {
for (ll a = 1; a * a + b * b <= N; a++) {
if (__gcd(a, b) != 1) continue;
ll norm = a * a + b * b;
for (ll k = 1; k * norm <= N; k++) {
ll cnt = N / (k * norm);
part2 += 2 * k * a * cnt;
}
}
}
printf("%lld\n", part1 + part2);
return 0;
}
import math
def solve():
N = 10**8
# Part 1: sum_{d=1}^{N} d * floor(N/d) via hyperbola method
part1 = 0
d = 1
while d <= N:
q = N // d
d_max = N // q
part1 += q * (d + d_max) * (d_max - d + 1) // 2
d = d_max + 1
# Part 2: Gaussian integer contributions
part2 = 0
for b in range(1, int(math.isqrt(N)) + 1):
if b * b + 1 > N:
break
for a in range(1, int(math.isqrt(N - b * b)) + 1):
if math.gcd(a, b) != 1:
continue
norm = a * a + b * b
if norm > N:
break
k = 1
while k * norm <= N:
q = N // (k * norm)
k_max = N // (q * norm)
s = (k + k_max) * (k_max - k + 1) // 2
part2 += 2 * a * q * s
k = k_max + 1
print(part1 + part2)
solve()