Divisor Square Sum
For a positive integer n, let sigma_2(n) denote the sum of the squares of the divisors of n: sigma_2(n) = sum_(d | n) d^2 For example, sigma_2(10) = 1^2 + 2^2 + 5^2 + 10^2 = 130. Find the sum of al...
Problem Statement
This archive keeps the full statement, math, and original media on the page.
For a positive integer \(n\), let \(\sigma _2(n)\) be the sum of the squares of its divisors. For example, \[\sigma _2(10) = 1 + 4 + 25 + 100 = 130.\] Find the sum of all \(n\), \(0 < n < 64\,000\,000\) such that \(\sigma _2(n)\) is a perfect square.
Problem 211: Divisor Square Sum
Mathematical Development
Definition 1. For , the divisor power sum function is . The case gives the sum-of-squares-of-divisors function.
Theorem 1 (Multiplicativity of ). The function is multiplicative: if , then .
Proof. Let with . We claim the map
is a bijection.
Surjectivity. Let . Write . Since , each prime divides at most one of or . Set
Then , , and .
Injectivity. If with and , then , so . By symmetry , hence and then .
Therefore
Lemma 1 (Geometric sum for prime powers). For a prime and integer ,
Proof. The divisors of are precisely . Hence
which is a finite geometric series with ratio .
Proposition 1 (Overflow bound). For , unsigned 64-bit integers suffice to store in the sieve implementation.
Theorem 2 (Segmented factorization formula). Let
be the prime factorization of . If we process each prime factor once, multiply an accumulator by
and remove from a working copy of , then the final accumulator equals . If a residual factor remains after all primes up to have been removed, that residual factor is prime and contributes a final factor .
Proof. The product formula
follows immediately from Theorem 1 and Lemma 1.
Now remove the prime powers from a working copy of . When all primes up to have been processed, any remaining factor cannot be composite, because a composite number has a prime divisor at most its square root. Therefore the remaining factor is either or a single prime, and multiplying by completes the product for .
Lemma 2 (Perfect square detection). A nonnegative integer is a perfect square if and only if . Integer square root can be computed exactly via Newton’s method or a built-in isqrt.
Editorial
The useful structural fact is that is multiplicative, so once the prime factorization of is known we can recover from the geometric-series factors
Factoring each integer from scratch would still be too slow, so the implementation works in blocks. Inside one block we keep the current values of the integers and an accumulator for their product. Then, for each prime , we walk through the multiples of inside that block, strip off the full power of , and multiply the accumulator by the corresponding prime-power contribution.
After all small primes are processed, each number has at most one prime factor left. Multiplying by finishes , and then a single integer-square-root check tells us whether that value is a square. This keeps the same mathematics as the direct formula, but avoids storing a length- divisor table in Python.
Pseudocode
Set N = 64,000,000 and choose a block size B.
Generate all primes up to sqrt(N - 1).
answer = 0
For each block [L, R):
values[i] = L + i for every index in the block
sigma2[i] = 1 for every index in the block
For each prime p in the prime list:
Find the first multiple of p inside [L, R)
For each multiple m of p inside the block:
contribution = 1
power = 1
While values[m - L] is divisible by p:
Divide values[m - L] by p
power = power * p^2
contribution = contribution + power
Multiply sigma2[m - L] by contribution
For each position i in the block:
If values[i] > 1:
Multiply sigma2[i] by 1 + values[i]^2
r = integer square root of sigma2[i]
If r * r = sigma2[i]:
answer += L + i
Return answer
Complexity Analysis
- Time: Roughly arithmetic over all blocks. Each prime visits its multiples, and each prime factor is removed only as many times as its exponent occurs.
- Space: , where is the chosen block size.
Answer
Code
Each problem page includes the exact C++ and Python source files from the local archive.
#include <bits/stdc++.h>
using namespace std;
int main() {
const int N = 64000000;
vector<unsigned long long> sigma2(N, 0);
for (long long d = 1; d < N; d++) {
long long d2 = d * d;
for (long long k = d; k < N; k += d)
sigma2[k] += d2;
}
long long answer = 0;
for (int n = 1; n < N; n++) {
unsigned long long s = sigma2[n];
unsigned long long r = (unsigned long long)sqrt((double)s);
while (r * r > s) r--;
while ((r + 1) * (r + 1) <= s) r++;
if (r * r == s)
answer += n;
}
cout << answer << endl;
return 0;
}
from math import isqrt
def primes_up_to(limit):
sieve = bytearray(b"\x01") * (limit + 1)
sieve[0:2] = b"\x00\x00"
for p in range(2, isqrt(limit) + 1):
if sieve[p]:
sieve[p * p : limit + 1 : p] = b"\x00" * (((limit - p * p) // p) + 1)
return [p for p in range(2, limit + 1) if sieve[p]]
def solve():
limit = 64_000_000
block_size = 1_000_000
primes = primes_up_to(isqrt(limit - 1))
answer = 0
for block_start in range(1, limit, block_size):
block_end = min(limit, block_start + block_size)
size = block_end - block_start
values = [block_start + i for i in range(size)]
sigma2 = [1] * size
for p in primes:
p2 = p * p
first = ((block_start + p - 1) // p) * p
for multiple in range(first, block_end, p):
idx = multiple - block_start
term = 1
power = 1
while values[idx] % p == 0:
values[idx] //= p
power *= p2
term += power
sigma2[idx] *= term
for offset, remaining in enumerate(values):
if remaining > 1:
sigma2[offset] *= 1 + remaining * remaining
total = sigma2[offset]
root = isqrt(total)
if root * root == total:
answer += block_start + offset
print(answer)
if __name__ == "__main__":
solve()