Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Optimizing Integer Factorization with Logarithmic Comparison for Minimal Product

Tech 2

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:

  1. Precompute primes up to a sufficient limit (e.g., 600) and their natural logarithms.
  2. For each integer up to n, precompute its divisors to speed up DFS.
  3. Define a structure to store exponents k_i for primes, with a comparison operator based on logarithmic sums.
  4. Use DFS to iterate over factorizations of n, updating the minimal logarithmic sum.
  5. 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;
}

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.