Integer Partition Asymptotics
Let p(n) denote the number of integer partitions of n. Find p(200) mod 10^9+7. A partition of n is a multiset of positive integers summing to n. For example, p(5) = 7: the partitions are 5, 4+1, 3+...
Problem Statement
This archive keeps the full statement, math, and original media on the page.
Given a right-angled triangle with integer sides, the smaller angle formed by the two medians drawn on the the two perpendicular sides is denoted by $\theta$.

Let $f(\alpha, L)$ denote the sum of the sides of the right-angled triangle minimizing the absolute difference between $\theta$ and $\alpha$ among all right-angled triangles with integer sides and hypotenuse not exceeding $L$.
If more than one triangle attains the minimum value, the triangle with the maximum area is chosen. All angles in this problem are measured in degrees.
For example, $f(30,10^2)=198$ and $f(10,10^6)= 1600158$.
Define $F(N,L)=\sum_{n=1}^{N}f\left(\sqrt[3]{n},L\right)$.
You are given $F(10,10^6)= 16684370$.
Find $F(45000, 10^{10})$.
Problem 904: Integer Partition Asymptotics
Mathematical Analysis
Generating Function
The partition function has a beautiful infinite product generating function:
Proof. Each factor generates the choice of how many copies of the part to include. The product over all generates all possible multisets of positive integers, which are exactly the partitions.
Euler’s Pentagonal Number Theorem
Euler discovered the complementary identity:
The exponents are the generalized pentagonal numbers:
Proof sketch. Euler’s proof uses the identity where is the Gaussian binomial, and takes . Franklin’s involution provides a bijective proof by pairing terms in the expansion.
Recurrence from Pentagonal Numbers
Multiplying (1) and (2):
Extracting the coefficient of for :
where the sum runs over and we set for . This gives an algorithm since , so at most terms are non-zero.
Hardy-Ramanujan Asymptotic Formula
The celebrated Hardy-Ramanujan formula (1918) gives:
For : , so .
Rademacher’s Exact Formula
Rademacher (1937) refined (4) into an exact convergent series:
where involves Dedekind sums .
Concrete Values and Verification
| HR approximation | Ratio | ||
|---|---|---|---|
| 1 | 1 | 0.58 | 1.72 |
| 5 | 7 | 5.45 | 1.28 |
| 10 | 42 | 37.3 | 1.13 |
| 20 | 627 | 600 | 1.05 |
| 50 | 204226 | 200686 | 1.02 |
| 100 | 190569292 | 189904147 | 1.004 |
| 200 | 3972999029388 | 3970951.. | 1.001 |
The Hardy-Ramanujan approximation improves rapidly with .
Derivation of the DP Algorithm
Algorithm 1: Standard DP (Knapsack / Coin Change)
Treat each integer as a “coin” with unlimited supply. The number of ways to make change for using coins is built bottom-up:
dp[0] = 1
for k = 1 to n:
for j = k to n:
dp[j] += dp[j - k]
Proof of correctness. After processing coin , counts partitions of using parts from . The outer loop order ensures each partition is counted once (parts are added in non-decreasing order).
Algorithm 2: Pentagonal Number Recurrence
Using (3), compute in sequence. Each requires summing previously computed values.
Algorithm 3: Matrix Method
Not directly applicable to the partition function (unlike Fibonacci), but the generating function can be evaluated using FFT-based polynomial multiplication for the truncated product (1).
Proof of Correctness
Theorem. The DP algorithm correctly computes for .
Proof. The DP implements the generating function product (1) truncated at degree 200. Each factor is incorporated by the inner loop update . After all values are processed, .
Cross-check. . Modular reduction: … Computing directly: .
. Remainder: . But ? No: , so we need another reduction. Actually . This gives . Remainder: . So .
Complexity Analysis
- DP (Algorithm 1): time, space. For : about 20,000 operations.
- Pentagonal recurrence (Algorithm 2): time, space. Slightly faster asymptotically.
- Rademacher series (Algorithm 3): with sufficient precision arithmetic. Optimal but complex to implement.
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 904: Integer Partition Asymptotics
*
* Compute p(200) mod 10^9 + 7, where p(n) = number of integer partitions of n.
*
* Two methods:
* 1. Standard DP (coin-change): O(n^2) time, O(n) space
* 2. Pentagonal number recurrence: O(n^{3/2}) time, O(n) space
*
* Identity: p(n) = sum_{j!=0} (-1)^{j+1} p(n - j(3j-1)/2)
*/
const long long MOD = 1e9 + 7;
const int N = 200;
/*
* Method 1: Coin-change DP
*
* Each integer k in {1,...,n} acts as a "coin" with unlimited supply.
* dp[j] accumulates the number of partitions of j using parts <= k.
*/
long long solve_dp() {
vector<long long> dp(N + 1, 0);
dp[0] = 1;
for (int k = 1; k <= N; k++) {
for (int j = k; j <= N; j++) {
dp[j] = (dp[j] + dp[j - k]) % MOD;
}
}
return dp[N];
}
/*
* Method 2: Pentagonal number recurrence
*
* p(n) = p(n-1) + p(n-2) - p(n-5) - p(n-7) + p(n-12) + ...
*
* Generalized pentagonal numbers: w(j) = j(3j-1)/2 for j = 1,-1,2,-2,...
* Sign pattern: +, +, -, -, +, +, ...
*/
long long solve_pentagonal() {
vector<long long> p(N + 1, 0);
p[0] = 1;
for (int n = 1; n <= N; n++) {
long long val = 0;
int sign = 1;
for (int j = 1; ; j++) {
// Two pentagonal numbers per j
int w1 = j * (3 * j - 1) / 2; // positive j
int w2 = j * (3 * j + 1) / 2; // negative j
if (w1 > n) break;
val = (val + sign * p[n - w1] % MOD + MOD) % MOD;
if (w2 <= n)
val = (val + sign * p[n - w2] % MOD + MOD) % MOD;
sign = -sign;
}
p[n] = val;
}
return p[N];
}
int main() {
long long ans1 = solve_dp();
long long ans2 = solve_pentagonal();
// Cross-check both methods
assert(ans1 == ans2);
// Verify small known values
// p(0)=1, p(1)=1, p(2)=2, p(3)=3, p(4)=5, p(5)=7
vector<long long> dp(11, 0);
dp[0] = 1;
for (int k = 1; k <= 10; k++)
for (int j = k; j <= 10; j++)
dp[j] += dp[j - k];
assert(dp[0] == 1 && dp[1] == 1 && dp[2] == 2);
assert(dp[3] == 3 && dp[4] == 5 && dp[5] == 7);
cout << ans1 << endl;
return 0;
}
"""
Problem 904: Integer Partition Asymptotics
Let p(n) denote the number of integer partitions of n. Find p(200) mod 10^9+7.
Key identities:
GF: sum p(n) x^n = prod 1/(1-x^k)
Pentagonal: prod (1-x^k) = sum (-1)^j x^{j(3j-1)/2}
Recurrence: p(n) = sum (-1)^{j+1} p(n - w_j) where w_j = j(3j-1)/2
Methods:
1. Standard DP (knapsack/coin-change) - O(n^2)
2. Pentagonal number recurrence - O(n^{3/2})
3. Exact computation with Hardy-Ramanujan verification
"""
from math import factorial, sqrt, pi, exp, log
MOD = 10**9 + 7
def partition_dp(n: int):
"""Compute p(n) exactly using the coin-change DP.
dp[0] = 1; for each part size k, update dp[j] += dp[j-k].
After processing all k, dp[n] = p(n).
"""
dp = [0] * (n + 1)
dp[0] = 1
for k in range(1, n + 1):
for j in range(k, n + 1):
dp[j] += dp[j - k]
return dp[n]
def partition_dp_mod(n: int, mod: int):
"""Compute p(n) mod m using the coin-change DP."""
dp = [0] * (n + 1)
dp[0] = 1
for k in range(1, n + 1):
for j in range(k, n + 1):
dp[j] = (dp[j] + dp[j - k]) % mod
return dp[n]
def generalized_pentagonal():
"""Generate generalized pentagonal numbers j(3j-1)/2 for j = 1,-1,2,-2,..."""
j = 1
while True:
yield j * (3 * j - 1) // 2 # positive j
yield (-j) * (3 * (-j) - 1) // 2 # negative j (= j*(3j+1)/2)
j += 1
def partition_pentagonal(n: int):
"""Compute p(0), p(1), ..., p(n) using the pentagonal number recurrence.
p(n) = sum_{j != 0} (-1)^{j+1} p(n - w_j)
where w_j = j(3j-1)/2 are generalized pentagonal numbers.
"""
p = [0] * (n + 1)
p[0] = 1
for m in range(1, n + 1):
total = 0
sign = 1
for j in range(1, m + 1):
# Two pentagonal numbers per j: w+ = j(3j-1)/2, w- = j(3j+1)/2
w1 = j * (3 * j - 1) // 2
w2 = j * (3 * j + 1) // 2
if w1 > m:
break
total += sign * p[m - w1]
if w2 <= m:
total += sign * p[m - w2]
sign = -sign
p[m] = total
return p[n]
def partition_pentagonal_all(n: int) -> list:
"""Return the full array [p(0), p(1), ..., p(n)]."""
p = [0] * (n + 1)
p[0] = 1
for m in range(1, n + 1):
total = 0
sign = 1
for j in range(1, m + 1):
w1 = j * (3 * j - 1) // 2
w2 = j * (3 * j + 1) // 2
if w1 > m:
break
total += sign * p[m - w1]
if w2 <= m:
total += sign * p[m - w2]
sign = -sign
p[m] = total
return p
# Hardy-Ramanujan approximation
def hardy_ramanujan(n: int) -> float:
"""Hardy-Ramanujan asymptotic formula for p(n)."""
if n <= 0:
return 1.0
return 1.0 / (4.0 * n * sqrt(3.0)) * exp(pi * sqrt(2.0 * n / 3.0))
# Solve
N = 200
p_exact = partition_dp(N)
p_pent = partition_pentagonal(N)
# Cross-check
assert p_exact == p_pent, f"Mismatch: DP={p_exact}, Pentagonal={p_pent}"
# Known values verification
known = {0: 1, 1: 1, 2: 2, 3: 3, 4: 5, 5: 7, 6: 11, 7: 15, 8: 22, 9: 30, 10: 42}
p_all = partition_pentagonal_all(max(known.keys()))
for n, val in known.items():
assert p_all[n] == val, f"p({n}) = {p_all[n]}, expected {val}"
# Modular answer
ans = p_exact % MOD
# Also verify modular DP
ans_mod = partition_dp_mod(N, MOD)
assert ans == ans_mod, f"Mod mismatch: {ans} vs {ans_mod}"
print(ans)