Optimizing Integer Factorization with Logarithmic Comparison for Minimal Product
Given an integer n, the task is to find the smallest positive integer N such that the number of divisors of N equals n. This problem leverages the divisor count formula: if N = ∏ p_i^{k_i}, then the number of divisors is ∏ (k_i + 1). Thus, n = ∏ (k_i + 1), where k_i are non-negative integers.
A naive approach involves factorizing n into its divisors (k_i + 1) and exploring all combinations to compute N = ∏ p_i^{k_i}, where p_i are consecutive primes. This can be done via depth-first search (DFS) over the factors of n, but direct computation of large integers (using big integer arithmetic) for each candidate N leads to high time complexity, approximately O(n√n).
To optimize, logarithmic properties are uitlized: log(xy) = log(x) + log(y) and log(x^y) = y log(x). Instead of comparing large integers driectly during DFS, compare their logarithms. This reduces computational overhead since logarithmic values are precomputed and stored.
Implementation steps:
- Precompute primes up to a sufficient limit (e.g., 600) and their natural logarithms.
- For each integer up to n, precompute its divisors to speed up DFS.
- Define a structure to store exponents k_i for primes, with a comparison operator based on logarithmic sums.
- Use DFS to iterate over factorizations of n, updating the minimal logarithmic sum.
- After DFS, compute the final integer N using fast exponentiation with the optimal exponents.
This optimization reduces runtime significant, e.g., from 700 ms to 20 ms for n = 50000.
Code example with restructured logic and renamed variables:
#include <bits/stdc++.h>
using namespace std;
struct BigInt {
vector<int> digits;
bool isNegative;
BigInt() : digits(1, 0), isNegative(false) {}
BigInt(long long x) {
if (x < 0) { isNegative = true; x = -x; }
else isNegative = false;
digits.clear();
do {
digits.push_back(x % 10);
x /= 10;
} while (x > 0);
}
bool operator<(const BigInt& other) const {
if (digits.size() != other.digits.size()) return digits.size() < other.digits.size();
for (int i = digits.size() - 1; i >= 0; --i)
if (digits[i] != other.digits[i]) return digits[i] < other.digits[i];
return false;
}
BigInt operator*(const BigInt& other) const {
BigInt result;
result.digits.assign(digits.size() + other.digits.size(), 0);
for (size_t i = 0; i < digits.size(); ++i)
for (size_t j = 0; j < other.digits.size(); ++j) {
result.digits[i + j] += digits[i] * other.digits[j];
result.digits[i + j + 1] += result.digits[i + j] / 10;
result.digits[i + j] %= 10;
}
while (result.digits.size() > 1 && result.digits.back() == 0) result.digits.pop_back();
result.isNegative = isNegative ^ other.isNegative;
return result;
}
BigInt pow(int exp) const {
if (exp == 0) return BigInt(1);
BigInt half = pow(exp / 2);
half = half * half;
if (exp % 2) half = half * (*this);
return half;
}
};
const int MAX_PRIME = 600;
vector<int> primes;
vector<double> logPrimes;
vector<vector<int>> divisors;
void sieve() {
vector<bool> isPrime(MAX_PRIME + 1, true);
isPrime[0] = isPrime[1] = false;
for (int i = 2; i * i <= MAX_PRIME; ++i)
if (isPrime[i])
for (int j = i * i; j <= MAX_PRIME; j += i)
isPrime[j] = false;
for (int i = 2; i <= MAX_PRIME; ++i)
if (isPrime[i]) {
primes.push_back(i);
logPrimes.push_back(log(i));
}
}
void precomputeDivisors(int n) {
divisors.resize(n + 1);
for (int i = 1; i <= n; ++i) {
for (int d = 2; d * d <= i; ++d) {
if (i % d == 0) {
divisors[i].push_back(d);
if (d != i / d) divisors[i].push_back(i / d);
}
}
divisors[i].push_back(i);
}
}
struct ExponentState {
vector<int> exponents;
bool operator<(const ExponentState& other) const {
double sum1 = 0, sum2 = 0;
for (size_t i = 0; i < exponents.size(); ++i) {
sum1 += exponents[i] * logPrimes[i];
sum2 += other.exponents[i] * logPrimes[i];
}
return sum1 < sum2;
}
void adjust(int idx, int delta) { exponents[idx] += delta; }
};
ExponentState bestState;
void dfs(int remaining, ExponentState current, int primeIdx) {
if (bestState < current) return;
if (remaining == 1) {
if (current < bestState) bestState = current;
return;
}
for (int factor : divisors[remaining]) {
current.adjust(primeIdx, factor - 1);
dfs(remaining / factor, current, primeIdx + 1);
current.adjust(primeIdx, -(factor - 1));
}
}
int main() {
int n;
cin >> n;
sieve();
precomputeDivisors(n);
bestState.exponents.assign(primes.size(), 10000);
ExponentState start;
start.exponents.assign(primes.size(), 0);
dfs(n, start, 0);
BigInt result(1);
for (size_t i = 0; i < primes.size(); ++i) {
if (bestState.exponents[i] == 0) break;
result = result * BigInt(primes[i]).pow(bestState.exponents[i]);
}
for (int i = result.digits.size() - 1; i >= 0; --i) cout << result.digits[i];
cout << endl;
return 0;
}