Cyclotomic Polynomial Evaluation
The n -th cyclotomic polynomial Phi_n(x) is defined as the minimal polynomial over Q whose roots are the primitive n -th roots of unity. Compute: S = sum_(n=1)^500 Phi_n(2) (mod 10^9 + 7)
Problem Statement
This archive keeps the full statement, math, and original media on the page.
In Poker a straight is exactly five cards of sequential rank NOT all of the same suit. In this problem an ace can rank either high as in A-K-Q-J-10 or low as in 5-4-3-2-A, but cannot simultaneously rank both high and low, so Q-K-A-2-3 is not allowed.
There are
There are
Find the number of ways of choosing eight disjoint straights from a single
In this the order of choosing the straights does not matter.
Problem 987: Cyclotomic Polynomial Evaluation
Mathematical Analysis
Definition and Fundamental Identity
The cyclotomic polynomial is:
Its degree is (Euler’s totient). The fundamental factorization of over is:
Mobius Inversion Formula
Applying Mobius inversion to the logarithm of (1):
where is the Mobius function. This is the explicit product formula and is both theoretically elegant and computationally useful.
Evaluating at
Substituting into (2):
Alternatively, from (1) directly:
This gives the divisor recurrence:
Key Properties of
-
Mersenne connection: For prime , , the -th Mersenne number.
-
Aurifeuillean factorizations: For certain , admits algebraic factorizations beyond the cyclotomic structure (e.g., has a non-trivial factorization discovered by Aurifeuille).
-
Divisibility: for all , and the multiplicative order of 2 modulo any prime is exactly .
-
Growth rate: as , since the roots of lie on the unit circle and for most .
Concrete Examples
| 1 | 1 | ||
| 2 | 1 | ||
| 3 | 2 | ||
| 4 | 2 | ||
| 5 | 4 | ||
| 6 | 2 | ||
| 7 | 6 | ||
| 8 | 4 | ||
| 10 | 4 | ||
| 12 | 4 |
Note the surprising result . In general, small values of occur when has many small prime factors.
Derivation
Algorithm 1: Divisor Recurrence (used in implementation)
Compute for using (5):
- For each , compute via modular exponentiation.
- Compute using previously computed values.
- Set , where is the modular inverse via Fermat’s little theorem ( is prime).
Algorithm 2: Mobius Product (alternative)
Using (3) directly:
- Precompute for via a sieve.
- Precompute for .
- For each , compute .
Factors with contribute 1 (skip). Factors with contribute a modular inverse.
Verification
Both algorithms yield identical results. Cross-check: .
From (4): . Correct.
Proof of Correctness
Theorem. The identity holds in .
Proof. The roots of are all -th roots of unity . Each such root is a primitive -th root of unity for exactly one (namely ). Since is the minimal polynomial of the primitive -th roots, the factorization follows from unique factorization in .
Corollary. The Mobius inversion formula (2) follows by applying -inversion to .
Lemma. For prime , the modular computation is exact: for all .
Proof. If , then , i.e., . One verifies that and is prime. So the only with are . But and , neither divisible by .
Complexity Analysis
- Divisor recurrence: for enumerating divisors + for modular exponentiations = total.
- Mobius product: Same complexity with a different constant factor.
- Space: to store the computed values.
For , both algorithms run in microseconds.
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 987: Cyclotomic Polynomial Evaluation
*
* Compute S = sum_{n=1}^{500} Phi_n(2) mod (10^9 + 7).
*
* Two methods implemented:
* 1. Divisor recurrence: Phi_n(2) = (2^n - 1) / prod_{d|n, d<n} Phi_d(2)
* 2. Mobius product: Phi_n(2) = prod_{d|n} (2^d - 1)^{mu(n/d)}
*
* Both yield the same result; we use method 1 as primary and method 2
* as a cross-check.
*/
const long long MOD = 1e9 + 7;
const int N = 500;
long long power(long long base, long long exp, long long mod) {
long long result = 1;
base %= mod;
while (exp > 0) {
if (exp & 1) result = result * base % mod;
base = base * base % mod;
exp >>= 1;
}
return result;
}
long long modinv(long long a, long long mod = MOD) {
return power(a, mod - 2, mod);
}
vector<int> get_divisors(int n) {
vector<int> divs;
for (int d = 1; (long long)d * d <= n; d++) {
if (n % d == 0) {
divs.push_back(d);
if (d != n / d) divs.push_back(n / d);
}
}
sort(divs.begin(), divs.end());
return divs;
}
// Method 1: Divisor recurrence
// Phi_n(2) = (2^n - 1) / prod_{d|n, d<n} Phi_d(2)
long long solve_recurrence() {
vector<long long> phi(N + 1, 0);
long long total = 0;
for (int n = 1; n <= N; n++) {
long long num = (power(2, n, MOD) - 1 + MOD) % MOD;
long long den = 1;
for (int d : get_divisors(n)) {
if (d < n) {
den = den * phi[d] % MOD;
}
}
phi[n] = num % MOD * modinv(den) % MOD;
total = (total + phi[n]) % MOD;
}
return total;
}
// Method 2: Mobius product formula
// Phi_n(2) = prod_{d|n} (2^d - 1)^{mu(n/d)}
long long solve_mobius() {
// Sieve Mobius function
vector<int> mu(N + 1, 0);
mu[1] = 1;
vector<bool> is_prime(N + 1, true);
vector<int> primes;
for (int i = 2; i <= N; i++) {
if (is_prime[i]) {
primes.push_back(i);
mu[i] = -1;
}
for (int p : primes) {
if ((long long)i * p > N) break;
is_prime[i * p] = false;
if (i % p == 0) {
mu[i * p] = 0;
break;
}
mu[i * p] = -mu[i];
}
}
// Precompute 2^d - 1 mod p
vector<long long> pow2m1(N + 1);
for (int d = 1; d <= N; d++) {
pow2m1[d] = (power(2, d, MOD) - 1 + MOD) % MOD;
}
long long total = 0;
for (int n = 1; n <= N; n++) {
long long phi_n = 1;
for (int d : get_divisors(n)) {
int m = mu[n / d];
if (m == 1) {
phi_n = phi_n * pow2m1[d] % MOD;
} else if (m == -1) {
phi_n = phi_n * modinv(pow2m1[d]) % MOD;
}
// m == 0: skip (contributes 1)
}
total = (total + phi_n) % MOD;
}
return total;
}
int main() {
long long ans1 = solve_recurrence();
long long ans2 = solve_mobius();
// Cross-check both methods
assert(ans1 == ans2);
cout << ans1 << endl;
return 0;
}
"""
Problem 987: Cyclotomic Polynomial Evaluation
The n-th cyclotomic polynomial Phi_n(x) is the minimal polynomial over Q
whose roots are the primitive n-th roots of unity. We compute:
S = sum_{n=1}^{500} Phi_n(2) mod (10^9 + 7)
Key identity: x^n - 1 = prod_{d|n} Phi_d(x)
Mobius form: Phi_n(x) = prod_{d|n} (x^d - 1)^{mu(n/d)}
Recurrence: Phi_n(x) = (x^n - 1) / prod_{d|n, d<n} Phi_d(x)
"""
from math import gcd
MOD = 10**9 + 7
# --- Mobius function sieve ---
def mobius_sieve(n: int):
"""Compute mu(k) for k = 0, 1, ..., n via linear sieve."""
mu = [0] * (n + 1)
mu[1] = 1
is_prime = [True] * (n + 1)
primes = []
for i in range(2, n + 1):
if is_prime[i]:
primes.append(i)
mu[i] = -1 # prime => mu = -1
for p in primes:
if i * p > n:
break
is_prime[i * p] = False
if i % p == 0:
mu[i * p] = 0 # p^2 divides i*p
break
else:
mu[i * p] = -mu[i]
return mu
def divisors(n: int):
"""Return sorted list of divisors of n."""
divs = []
d = 1
while d * d <= n:
if n % d == 0:
divs.append(d)
if d != n // d:
divs.append(n // d)
d += 1
return sorted(divs)
# --- Method 1: Divisor recurrence ---
def solve_recurrence(N: int, mod: int):
"""Compute Phi_n(2) mod p for n=1..N using the divisor recurrence.
Phi_n(2) = (2^n - 1) / prod_{d|n, d<n} Phi_d(2) mod p
"""
phi = [0] * (N + 1)
for n in range(1, N + 1):
num = (pow(2, n, mod) - 1) % mod
den = 1
for d in divisors(n):
if d < n:
den = den * phi[d] % mod
phi[n] = num * pow(den, mod - 2, mod) % mod
return phi, sum(phi[1:]) % mod
# --- Method 2: Mobius product formula ---
def solve_mobius(N: int, mod: int):
"""Compute Phi_n(2) mod p using the Mobius product formula.
Phi_n(2) = prod_{d|n} (2^d - 1)^{mu(n/d)} mod p
"""
mu = mobius_sieve(N)
pow2m1 = [0] * (N + 1) # 2^d - 1 mod p
for d in range(1, N + 1):
pow2m1[d] = (pow(2, d, mod) - 1) % mod
phi = [0] * (N + 1)
for n in range(1, N + 1):
result = 1
for d in divisors(n):
m = mu[n // d]
if m == 1:
result = result * pow2m1[d] % mod
elif m == -1:
result = result * pow(pow2m1[d], mod - 2, mod) % mod
# m == 0 contributes factor 1
phi[n] = result
return phi, sum(phi[1:]) % mod
# --- Method 3: Exact computation (small n, for verification) ---
def cyclotomic_exact(N: int) -> list:
"""Compute exact Phi_n(2) for n = 1..N (no modular reduction)."""
phi = [0] * (N + 1)
for n in range(1, N + 1):
num = 2**n - 1
den = 1
for d in divisors(n):
if d < n:
den *= phi[d]
phi[n] = num // den
return phi
# --- Compute and verify ---
N = 500
phi_rec, ans_rec = solve_recurrence(N, MOD)
phi_mob, ans_mob = solve_mobius(N, MOD)
assert ans_rec == ans_mob, f"Mismatch: {ans_rec} != {ans_mob}"
# Verify small cases with exact computation
phi_exact = cyclotomic_exact(50)
expected = {1: 1, 2: 3, 3: 7, 4: 5, 5: 31, 6: 3, 7: 127, 8: 17, 10: 11, 12: 13}
for n, val in expected.items():
assert phi_exact[n] == val, f"Phi_{n}(2) = {phi_exact[n]}, expected {val}"
# Verify fundamental identity: prod_{d|n} Phi_d(2) = 2^n - 1
for n in range(1, 51):
product = 1
for d in divisors(n):
product *= phi_exact[d]
assert product == 2**n - 1, f"Identity failed for n={n}"
# Verify Mobius formula against exact for small n
for n in range(1, 51):
assert phi_rec[n] == phi_exact[n] % MOD
print(ans_rec)