#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#ifndef __BIG_INT_H
#define __BIG_INT_H
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <string>
template<int N> struct Pow10 { static const uint64_t pow = 10 * Pow10<N-1>::pow; };
template<> struct Pow10<0> { static const uint64_t pow = 1; };
template <int BASE_POW, int LEN>
class BigIntTemplate {
public:
explicit BigIntTemplate(uint64_t x = 0) {
m_len = 10;
memset(m_cif, 0, sizeof(m_cif));
for (uint32_t i = 0; x; ++i) {
m_cif[i] = x % sm_base;
x /= sm_base;
}
fix();
}
explicit BigIntTemplate(const std::string& number) {
const char* digits = number.c_str();
m_len = 0;
memset(m_cif, 0, sizeof(m_cif));
char buff[sm_base_pow + 5];
int poz = strlen(digits) - sm_base_pow;
while (poz >= 0) {
memset(buff, 0, sizeof(buff));
strncpy(buff, digits + poz, sm_base_pow);
m_cif[m_len++] = atoi(buff);
poz -= sm_base_pow;
}
memset(buff, 0, sizeof(buff));
strncpy(buff, digits, sm_base_pow + poz);
m_cif[m_len++] = atoi(buff);
fix();
}
BigIntTemplate& operator*=(uint32_t scalar) {
for (int i = m_len - 1; i >= 0; --i) {
uint64_t temp = (uint64_t)m_cif[i] * scalar;
m_cif[i + 2] += (temp / sm_base) / sm_base;
m_cif[i + 1] += (temp / sm_base) % sm_base;
m_cif[i] = temp % sm_base;
}
m_len += 2;
fix();
return *this;
}
BigIntTemplate& operator+=(const BigIntTemplate& other) {
for (uint32_t i = 0; i < other.m_len; ++i) {
m_cif[i] += other.m_cif[i];
}
m_len = std::max(m_len, other.m_len);
fix();
return *this;
}
BigIntTemplate& operator+=(uint32_t other) {
m_cif[0] += other;
fix();
return *this;
}
BigIntTemplate& operator-=(const BigIntTemplate& other) {
uint32_t borrow = 0;
for (uint32_t i = 0; i < other.m_len || borrow; ++i) {
uint32_t temp = (borrow + other.m_cif[i] + sm_base - 1 - m_cif[i]) / sm_base;
m_cif[i] += temp * sm_base - other.m_cif[i] - borrow;
borrow = temp;
}
fix();
return *this;
}
BigIntTemplate& operator-=(uint32_t other) {
for (uint32_t i = 0; other; ++i) {
if (other <= m_cif[i]) {
m_cif[i] -= other;
break;
}
uint32_t borrow = (other + sm_base - 1 - m_cif[i]) / sm_base;
m_cif[i] += borrow * sm_base - other;
other = borrow;
}
fix();
return *this;
}
BigIntTemplate operator*(const BigIntTemplate& other) const {
BigIntTemplate result(0);
for (uint32_t i = 0; i < m_len; ++i)
for (uint32_t j = 0; j < other.m_len; ++j) {
uint64_t temp = (uint64_t)m_cif[i] * (uint64_t)other.m_cif[j] + result.m_cif[i + j];
result.m_cif[i + j] = temp % sm_base;
result.m_cif[i + j + 1] += temp / sm_base;
}
result.m_len = m_len + other.m_len;
result.fix();
return result;
}
BigIntTemplate& operator/=(uint32_t div) {
uint64_t num = 0;
for (int i = m_len - 1; i >= 0; --i) {
num *= sm_base;
num += m_cif[i];
m_cif[i] = num / div;
num %= div;
}
fix();
return *this;
}
bool operator<(const BigIntTemplate& other) const { return compare(other) < 0; }
bool operator<=(const BigIntTemplate& other) const { return compare(other) <= 0; }
bool operator>(const BigIntTemplate& other) const { return compare(other) > 0; }
bool operator>=(const BigIntTemplate& other) const { return compare(other) >= 0; }
bool operator==(const BigIntTemplate& other) const { return compare(other) == 0; }
bool operator!=(const BigIntTemplate& other) const { return compare(other) != 0; }
BigIntTemplate operator+(const BigIntTemplate& other) const {
BigIntTemplate result(*this);
result += other;
return result;
}
BigIntTemplate operator+(uint32_t other) const {
BigIntTemplate result(*this);
result += other;
return result;
}
BigIntTemplate operator-(const BigIntTemplate& other) const {
BigIntTemplate result(*this);
result -= other;
return result;
}
BigIntTemplate operator-(uint32_t other) const {
BigIntTemplate result(*this);
result -= other;
return result;
}
void print(std::string& output) const {
if (!m_len) { output = "0"; return; }
output.clear();
add_digit(m_cif[m_len - 1], false, output);
for (int i = m_len - 2; i >= 0; --i)
add_digit(m_cif[i], true, output);
}
std::string print() const {
std::string result;
print(result);
return result;
}
void raw_print() const {
printf("%lu :", (unsigned long)m_len);
for (int i = m_len - 1; i >= 0; --i)
printf(" %lu", (unsigned long)m_cif[i]);
printf("\n");
}
int compare(const BigIntTemplate& other) const {
if (m_len != other.m_len) {
return (m_len < other.m_len) ? -1 : 1;
}
for (int i = m_len - 1; i >= 0; --i)
if (m_cif[i] != other.m_cif[i])
return (m_cif[i] < other.m_cif[i]) ? -1 : 1;
return 0;
}
bool all_ok() const {
for (uint32_t i = m_len; i < LEN; ++i)
if (m_cif[i]) return false;
for (uint32_t i = 0; i < m_len; ++i)
if (m_cif[i] < 0 || m_cif[i] >= sm_base)
return false;
return true;
}
private:
void fix() {
for (int i = 0; i < (signed)m_len; ++i) {
if (m_cif[i] >= sm_base) {
m_cif[i + 1] += m_cif[i] / sm_base;
m_cif[i] %= sm_base;
if (i + 1 == (signed)m_len) ++m_len;
}
}
while (m_len && m_cif[m_len - 1] == 0) --m_len;
}
void add_digit(uint32_t digit, bool force_len, std::string& str) const {
char lol_buffer[128];
sprintf(lol_buffer, "%%%lu.%lulu", sm_base_pow, sm_base_pow);
char buffer[128];
sprintf(buffer, force_len ? lol_buffer : "%lu", (unsigned long)digit);
str += buffer;
}
static const uint64_t sm_base_pow = BASE_POW;
static const uint64_t sm_base = Pow10<sm_base_pow>::pow;
uint32_t m_cif[LEN], m_len;
};
//typedef BigIntTemplate<8, 32> BigInt;
typedef BigIntTemplate<8, 64> BigInt8;
typedef BigIntTemplate<4, 128> BigInt4;
class BigInt {
public:
BigInt(uint64_t x) : bi8(x), bi4(x) { }
BigInt(const std::string& x) : bi8(x), bi4(x) { }
BigInt(const BigInt8& b8, const BigInt4& b4) : bi8(b8), bi4(b4) {}
BigInt operator*(const BigInt& other) const {
// pre_check(); other.pre_check();
BigInt8 r8(bi8 * other.bi8);
BigInt4 r4(bi4 * other.bi4);
BigInt result(r8, r4);
// result.post_check();
return result;
}
BigInt operator+(const BigInt& other) const {
// pre_check(); other.pre_check();
BigInt8 r8(bi8 + other.bi8);
BigInt4 r4(bi4 + other.bi4);
BigInt result(r8, r4);
// result.post_check();
return result;
}
BigInt operator-=(uint32_t x) {
pre_check();
bi8 -= x;
bi4 -= x;
post_check();
return *this;
}
BigInt& operator/=(uint32_t x) {
// pre_check();
bi8 /= x;
bi4 /= x;
// post_check();
return *this;
}
int compare(const BigInt& other) const {
// pre_check();
int result8 = bi8.compare(other.bi8);
int result4 = bi4.compare(other.bi4);
(void)result4;
// if (result4 != result8) exit(1);
return result8;
}
bool operator>(const BigInt& other) const { return compare(other) > 0; }
bool operator==(const BigInt& other) const { return compare(other) == 0; }
bool operator<=(const BigInt& other) const { return compare(other) <= 0; }
std::string print() const {
std::string s8 = bi8.print();
std::string s4 = bi4.print();
// if (s8 != s4) my_exit(1);
return s8;
}
private:
BigInt8 bi8;
BigInt4 bi4;
bool all_ok() const {
return bi8.all_ok() && bi4.all_ok() && bi8.print() == bi4.print();
}
void pre_check() const {
if (!all_ok()) for (;;);
}
void post_check() const {
if (!all_ok()) exit(1);
}
};
#endif // __BIG_INT_H
#define FISIN "numere2.in"
#define FISOUT "numere2.out"
#define MAXPOW 333
int bad_prime[MAXPOW];
BigInt fastExp(BigInt num, int pow, const BigInt& target, bool& too_big) {
if (pow == 0) { return BigInt(1); }
if (pow == 1) { return num; }
BigInt sqrt = fastExp(num, pow / 2, target, too_big);
if (too_big) return BigInt(1);
BigInt temp = sqrt * sqrt;
BigInt result = (pow & 1) ? (temp * num) : temp;
if (result > target) {
too_big = true;
return BigInt(1);
}
return result;
}
void update_en(BigInt& en, const BigInt& target, long pow) {
return;
/*
BigInt alt = target;
for (int i = 1; i < pow; ++i)
alt /= 2;
if (alt < en) en = alt;
*/
}
int main() {
FILE *fin = fopen(FISIN, "rt");
FILE *fout = fopen(FISOUT, "wt");
char buffer[128];
fscanf(fin, "%s", buffer);
BigInt target(buffer);
int power = 1;
BigInt en(target);
for (int i = 2; i < MAXPOW; ++i) {
if (bad_prime[i]) continue;
for (int j = i * 2; j < MAXPOW; j += i)
bad_prime[j] = 1;
update_en(en, target, i);
BigInt st(1);
while (st <= en) {
BigInt mid = st + en;
mid /= 2;
bool too_big = false;
BigInt pow = fastExp(mid, i, target, too_big);
if (!too_big && pow == target) {
power *= i;
target = mid;
en = target;
update_en(en, target, i);
--i;
break;
}
if (too_big || pow > target) {
en = mid; en -= 1;
} else {
st = mid + 1;
}
}
}
std::string output = target.print();
fprintf(fout, "%s\n%d\n", output.c_str(), power);
fclose(fout);
fclose(fin);
return 0;
}