Divisibility of Factorials
The smallest number m such that 10 divides m! is m = 5. The smallest number m such that 25 divides m! is m = 10. Let s(n) be the smallest number m such that n divides m!. So s(10) = 5 and s(25) = 1...
Problem Statement
This archive keeps the full statement, math, and original media on the page.
The smallest number \(m\) such that \(10\) divides \(m!\) is \(m=5\).
The smallest number \(m\) such that \(25\) divides \(m!\) is \(m=10\).
Let \(s(n)\) be the smallest number \(m\) such that \(n\) divides \(m!\).
So \(s(10)=5\) and \(s(25)=10\).
Let \(S(n)\) be \(\sum s(i)\) for \(2 \le i \le n\).
You are given \(S(100)=2012\).
Find \(S(10^8)\).
Problem 549: Divisibility of Factorials
Mathematical Analysis
Key Property: Multiplicativity over Prime Powers
If , then:
Proof: The factorizations in for different primes are independent. For , we need for every . Each condition is satisfied when . Thus the minimum satisfying all conditions simultaneously is the maximum.
Computing via Legendre’s Formula
By Legendre’s formula, the exponent of prime in is:
We need the smallest such that . Since must be a multiple of (otherwise ), we only check multiples of .
For a prime , . For , we search multiples of : until the factorial exponent reaches .
Editorial
For a prime power p^e, s(p^e) is the smallest m such that the exponent of p in m! >= e. By Legendre’s formula: v_p(m!) = sum(floor(m/p^k) for k=1,2,…). We use a sieve to find smallest prime factors, then factorize each n. We sieve primes** up to using a modified sieve. We then iterate over each prime : iterate through powers and for each, compute by finding the smallest multiple of whose factorial contains at least factors of . Finally, sieve approach: For each , compute of values over its prime power factorization. This is done during sieving: for each prime and each power , update all multiples.
Pseudocode
Sieve primes** up to $N = 10^8$ using a modified sieve
Initialize** an array `s[2..N]` where `s[i] = 0`
For each prime $p$**: iterate through powers $p^e \leq N$ and for each, compute $s(p^e)$ by finding the smallest multiple of $p$ whose factorial contains at least $e$ factors of $p$
Sieve approach**: For each $n$, compute $s(n) = \max$ of $s$ values over its prime power factorization. This is done during sieving: for each prime $p$ and each power $p^e$, update all multiples
Sum** all $s(i)$ for $2 \leq i \leq N$
Correctness
Theorem. The method described above computes exactly the quantity requested in the problem statement.
Proof. The preceding analysis identifies the admissible objects and derives the formula, recurrence, or exhaustive search carried out by the algorithm. The computation evaluates exactly that specification, so every valid contribution is included once and no invalid contribution is counted. Therefore the returned value is the required answer.
Complexity Analysis
- Time: for the sieve, plus work proportional to the number of prime powers.
- Space: for the sieve and the array.
Answer
Code
Each problem page includes the exact C++ and Python source files from the local archive.
#include <bits/stdc++.h>
using namespace std;
/*
* Problem 549: Divisibility of Factorials
* Find S(10^8) where s(n) = smallest m such that n | m!
* Key: s(n) = max over prime power factors p^e of s(p^e)
* Use sieve to compute s(n) for all n up to N.
*/
const int N = 100000000; // 10^8
// s[i] = smallest m such that i | m!
// We store as short values relative approach: use int array
static int s[N + 1];
// Compute the p-adic valuation of m!
// i.e., the exponent of p in m!
long long factorial_val(int m, int p) {
long long v = 0;
long long pk = p;
while (pk <= m) {
v += m / pk;
if (pk > m / p) break; // prevent overflow
pk *= p;
}
return v;
}
// Find smallest m such that p^e | m!
// m must be a multiple of p
int find_s_prime_power(int p, int e) {
// Binary search: find smallest m (multiple of p) with factorial_val(m, p) >= e
// Lower bound: e (since val(e!) >= e/p + ... but we need at least e)
// Actually s(p^e) <= p * e (since val((pe)!) >= e + e/p + ... >= e)
// But we can do binary search on multiples of p
int lo = p, hi = (long long)p * e < N ? p * e : N;
// Ensure hi is multiple of p
hi = (hi / p) * p;
if (hi < p) hi = p;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
mid = (mid / p) * p;
if (mid < lo) mid = lo;
if (factorial_val(mid, p) >= e) {
hi = mid;
} else {
mid += p;
if (mid > hi) { lo = hi; break; }
lo = mid;
}
}
return lo;
}
int main() {
ios_base::sync_with_stdio(false);
// Initialize s array
// s[0] = s[1] = 0 (not used)
// For primes p, s[p] = p
// For prime powers p^e, s[p^e] = find_s_prime_power(p, e)
// For composite n, s[n] = max over prime power factors
// Step 1: Sieve to find smallest prime factor
vector<int> spf(N + 1, 0);
for (int i = 2; i <= N; i++) {
if (spf[i] == 0) { // i is prime
for (int j = i; j <= N; j += i) {
if (spf[j] == 0) spf[j] = i;
}
}
}
// Step 2: For each prime, precompute s(p^e) for all powers p^e <= N
// We'll store these in a map for quick lookup, but it's faster to
// just compute s(n) by factoring n using spf
// Step 3: Compute s(n) for each n from 2 to N
long long total = 0;
for (int n = 2; n <= N; n++) {
int tmp = n;
int result = 0;
while (tmp > 1) {
int p = spf[tmp];
int e = 0;
while (tmp % p == 0) {
tmp /= p;
e++;
}
// compute s(p^e)
int sp = find_s_prime_power(p, e);
result = max(result, sp);
}
total += result;
}
cout << total << endl;
return 0;
}
"""
Problem 549: Divisibility of Factorials
Find S(10^8) where s(n) = smallest m such that n | m!
S(n) = sum of s(i) for i = 2 to n
Key insight: s(n) = max(s(p^e)) over all prime power factors p^e of n.
For a prime power p^e, s(p^e) is the smallest m such that the exponent of p in m! >= e.
By Legendre's formula: v_p(m!) = sum(floor(m/p^k) for k=1,2,...).
We use a sieve to find smallest prime factors, then factorize each n.
"""
import sys
def solve():
N = 10**8
# Sieve of smallest prime factors
spf = list(range(N + 1))
for i in range(2, int(N**0.5) + 1):
if spf[i] == i: # i is prime
for j in range(i * i, N + 1, i):
if spf[j] == j:
spf[j] = i
def factorial_val(m, p):
"""Exponent of p in m!"""
v = 0
pk = p
while pk <= m:
v += m // pk
pk *= p
return v
def find_s_prime_power(p, e):
"""Smallest m such that p^e | m! (m is a multiple of p)."""
# Binary search on multiples of p
lo, hi = 1, e # in terms of multiplier k where m = k*p
# upper bound: k = e suffices since val(ep, p) >= e
while lo < hi:
mid = (lo + hi) // 2
if factorial_val(mid * p, p) >= e:
hi = mid
else:
lo = mid + 1
return lo * p
total = 0
for n in range(2, N + 1):
tmp = n
result = 0
while tmp > 1:
p = spf[tmp]
e = 0
while tmp % p == 0:
tmp //= p
e += 1
sp = find_s_prime_power(p, e)
if sp > result:
result = sp
total += result
print(total)
if __name__ == "__main__":
solve()