OI XXVII - tru

// https://szkopul.edu.pl/problemset/problem/iJJmCcYiYpjxJP682ai0jToE/site/?key=statement

// Trudny dylemat przedszkolanina

#include <bits/stdc++.h>

typedef unsigned long long ull;
typedef unsigned char u8;
typedef unsigned int u32;

const int NUM_PRIMES = 16;
const int primes[NUM_PRIMES] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53};

struct __attribute__((packed)) Candidate {
    ull val;
    u32 div_count;
    u8 exps_lo[8];
    u32 packed_hi;
};

ull N;
std::vector<Candidate> candidates;
ull approx_max_divisors = 0;

u8 current_exps_buffer[NUM_PRIMES];

bool can_reach_threshold(int p_idx, ull current_val, ull current_divs, ull threshold) {
    if (current_divs >= threshold) return true;
    if (p_idx >= NUM_PRIMES) return false;

    ull p = primes[p_idx];
    ull remaining = N / current_val;

    if (remaining < p) return false;

    ull temp_p = p;
    ull estimated_divs = current_divs;

    while (true) {
        estimated_divs *= 2;
        if (estimated_divs >= threshold) return true;
        if (remaining / p < temp_p) break;
        temp_p *= p;
    }
    return false;
}

void generate_candidates(int p_idx, ull current_val, ull current_divs) {
    if (current_divs >= approx_max_divisors * 0.5) {
        Candidate c;
        c.val = current_val;
        c.div_count = (u32)current_divs;

        for (int i = 0; i < 8; ++i)
            c.exps_lo[i] = current_exps_buffer[i];

        c.packed_hi = 0;
        for (int i = 8; i < 16; ++i) {
            c.packed_hi |= ((u32)current_exps_buffer[i] << ((i - 8) * 4));
        }

        candidates.push_back(c);
    }

    if (p_idx >= NUM_PRIMES) return;

    if (!can_reach_threshold(p_idx, current_val, current_divs, (ull)(approx_max_divisors * 0.5))) {
        return;
    }

    ull p = primes[p_idx];
    ull next_val = current_val;

    for (int k = 0;; ++k) {
        current_exps_buffer[p_idx] = k;

        generate_candidates(p_idx + 1, next_val, current_divs * (k + 1));

        if (N / p < next_val) break;
        next_val *= p;
    }
    current_exps_buffer[p_idx] = 0;
}

void find_approx_max(int p_idx, ull current_val, ull current_divs, int last_exp) {
    if (current_divs > approx_max_divisors) approx_max_divisors = current_divs;
    if (p_idx >= NUM_PRIMES) return;

    ull p = primes[p_idx];
    ull next_val = current_val;

    for (int k = 0; k <= last_exp; ++k) {
        find_approx_max(p_idx + 1, next_val, current_divs * (k + 1), k);
        if (N / p < next_val) break;
        next_val *= p;
    }
}

inline ull calc_gcd_divisors_fast(const Candidate& a, const Candidate& b) {
    ull gcd_divs = 1;

    for (int i = 0; i < 8; ++i) {
        u8 e1 = a.exps_lo[i];
        u8 e2 = b.exps_lo[i];
        gcd_divs *= ((e1 < e2 ? e1 : e2) + 1);
    }

    u32 p1 = a.packed_hi;
    u32 p2 = b.packed_hi;

    for (int i = 0; i < 8; ++i) {
        u8 e1 = p1 & 0xF;
        u8 e2 = p2 & 0xF;

        gcd_divs *= ((e1 < e2 ? e1 : e2) + 1);

        p1 >>= 4;
        p2 >>= 4;
    }

    return gcd_divs;
}

int main() {
    std::ios_base::sync_with_stdio(0);
    std::cin.tie(0);
    std::cout.tie(0);

    std::cin >> N;

    memset(current_exps_buffer, 0, sizeof(current_exps_buffer));

    find_approx_max(0, 1, 1, 60);
    if (approx_max_divisors == 0) approx_max_divisors = 1;

    candidates.reserve(600000);

    generate_candidates(0, 1, 1);

    ull best_union = 0;
    ull best_x = 1, best_y = 1;

    sort(candidates.begin(), candidates.end(), [](const Candidate& a, const Candidate& b) { return a.div_count > b.div_count; });

    if (!candidates.empty()) {
        best_union = candidates[0].div_count;
        best_x = candidates[0].val;
        best_y = candidates[0].val;
    } else {
        std::cout << "1\n1 1\n";
        return 0;
    }

    for (size_t i = 0; i < candidates.size(); ++i) {
        if (2 * (ull)candidates[i].div_count <= best_union) break;

        for (size_t j = i; j < candidates.size(); ++j) {
            if ((ull)candidates[i].div_count + (ull)candidates[j].div_count <= best_union) break;

            ull gcd_d = calc_gcd_divisors_fast(candidates[i], candidates[j]);
            ull union_size = (ull)candidates[i].div_count + (ull)candidates[j].div_count - gcd_d;

            if (union_size > best_union) {
                best_union = union_size;
                best_x = candidates[i].val;
                best_y = candidates[j].val;
            }
        }
    }

    std::cout << best_union << "\n";
    std::cout << best_x << " " << best_y << "\n";

    return 0;
}