Generalised Hamming Numbers
A Hamming number is a positive integer which has no prime factor larger than 5. We define a type- t generalised Hamming number as a positive integer which has no prime factor larger than t. How man...
Problem Statement
This archive keeps the full statement, math, and original media on the page.
A Hamming number is a positive number which has no prime factor larger than \(5\).
So the first few Hamming numbers are \(1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15\).
There are \(1105\) Hamming numbers not exceeding \(10^8\).
We will call a positive number a generalised Hamming number of type \(n\), if it has no prime factor larger than \(n\).
Hence the Hamming numbers are the generalised Hamming numbers of type \(5\).
How many generalised Hamming numbers of type \(100\) are there which don’t exceed \(10^9\)?
Problem 204: Generalised Hamming Numbers
Mathematical Development
Theorem (Fundamental Theorem of Arithmetic, applied to smooth numbers). Every 100-smooth number can be written uniquely as
where and are the 25 primes not exceeding 100. Thus the 100-smooth numbers up to are in bijection with the exponent vectors satisfying .
Proof. This is exactly the Fundamental Theorem of Arithmetic restricted to the prime set .
Theorem (Recursive Counting). Define as the number of positive integers whose prime factors all lie in . Then
with base case for all . The desired answer is .
Proof. Partition the valid numbers by the exponent of . For a fixed exponent , the remaining factor must be at most and may only use later primes. Summing over all admissible gives the recurrence.
Lemma (Exponent Bounds). For each prime , the maximum exponent satisfying is . In particular, , , , , and .
Proof. Direct comparison of powers with .
Editorial
Every type-100 Hamming number is assembled from the 25 primes at most 100, so the problem is really about choosing exponent vectors rather than testing integers one by one. Once the prime list is fixed, a depth-first search can decide the exponent of the current prime, shrink the remaining budget accordingly, and recurse to the next prime.
This visits only valid smooth numbers. Large primes have very small exponent ranges, so the recursion tree thins out quickly, and every leaf corresponds to one admissible product. That is much more efficient than scanning all numbers up to and factoring them.
Pseudocode
List all primes p_1, p_2, ..., p_25 not exceeding 100.
Define Count(index, current_product):
If index = 25:
return 1
p = p_index
total = 0
power = 1
While current_product * power <= 10^9:
total += Count(index + 1, current_product * power)
power *= p
return total
Return Count(0, 1)
Complexity Analysis
- Time: Proportional to the number of recursive states visited, which is on the order of the number of 100-smooth numbers up to .
- Space: for the recursion stack.
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 primes[] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97};
long long LIMIT = 1000000000LL;
int dfs(int idx, long long cur) {
if (idx == 25) return 1;
int count = 0;
long long power = 1;
while (cur * power <= LIMIT) {
count += dfs(idx + 1, cur * power);
power *= primes[idx];
}
return count;
}
int main() {
int answer = dfs(0, 1);
assert(answer == 2944730);
cout << answer << endl;
return 0;
}
"""
Problem 204: Generalised Hamming Numbers
Count 100-smooth numbers up to 10^9.
"""
def primes_up_to(n):
sieve = [True] * (n + 1)
sieve[0] = sieve[1] = False
for i in range(2, int(n**0.5) + 1):
if sieve[i]:
for j in range(i*i, n + 1, i):
sieve[j] = False
return [i for i in range(2, n + 1) if sieve[i]]
def count_smooth(primes, limit):
"""Count B-smooth numbers up to limit by recursive DFS."""
def dfs(idx, cur):
if idx == len(primes):
return 1
count = 0
p = primes[idx]
power = 1
while cur * power <= limit:
count += dfs(idx + 1, cur * power)
power *= p
return count
return dfs(0, 1)
def count_smooth_brute(B, limit):
"""Brute force: check each number for B-smoothness."""
count = 0
for n in range(1, limit + 1):
temp = n
for p in primes_up_to(B):
while temp % p == 0:
temp //= p
if temp == 1:
count += 1
return count
# Cross-check
p100 = primes_up_to(100)
assert len(p100) == 25
assert count_smooth_brute(5, 100) == count_smooth(primes_up_to(5), 100)
answer = count_smooth(p100, 10**9)
assert answer == 2944730, f"Expected 2944730, got {answer}"
print(answer)