#include <bits/stdc++.h>
#define rep(i, a, b) for (int i = a; i < (b); ++i)
#define trav(a, x) for (auto &a : x)
#define all(x) begin(x), end(x)
#define sz(x) (int)(x).size()
#define all(x) begin(x), end(x)
typedef long long ll;
using namespace std;
typedef vector<int> vi;
typedef unsigned long long ull;
struct timeit {
decltype(chrono::high_resolution_clock::now()) begin;
const string label;
timeit(string label = "???") : label(label) { begin = chrono::high_resolution_clock::now(); }
~timeit() {
auto end = chrono::high_resolution_clock::now();
auto duration = chrono::duration_cast<chrono::milliseconds>(end - begin).count();
cout << duration << "ms elapsed [" << label << "]" << endl;
}
};
mt19937_64 rng(5);
uniform_int_distribution<ull> uni(0, 1ull << 62);
int gcd_count = 0;
ull gcd(ull u, ull v) {
gcd_count++;
return __gcd(u, v);
}
// ull gcd(ull u, ull v) {
// gcd_count++;
// int shift;
// if (u == 0)
// return v;
// if (v == 0)
// return u;
// shift = __builtin_ctzl(u | v);
// u >>= __builtin_ctzl(u);
// do {
// v >>= __builtin_ctzl(v);
// if (u > v)
// swap(u, v);
// v = v - u;
// } while (v != 0);
// return u << shift;
// }
typedef long double ld;
int mul_cnt = 0;
ull mod_mul(ull a, ull b, ull M) {
mul_cnt++;
ll ret = a * b - M * ull(ld(a) * ld(b) / ld(M));
return ret + M * (ret < 0) - M * (ret >= (ll)M);
}
ull mod_pow(ull b, ull e, ull mod) {
ull ans = 1;
for (; e; b = mod_mul(b, b, mod), e /= 2)
if (e & 1)
ans = mod_mul(ans, b, mod);
return ans;
}
ull mod_add(ull x, ull y, ull p) { return (x += y) < p ? x : x - p; }
bool isPrime(ll n) {
if (n == 1)
return 0;
if (n < 2 || n % 6 % 4 != 1)
return n - 2 < 2;
ll A[] = {2, 13, 23, 1662803}, s = __builtin_ctzll(n - 1), d = n >> s;
for (auto a : A) { // ^ count trailing zeroes
ll p = mod_pow(a, d, n), i = s;
while (p != 1 && p != n - 1 && a % n && i--)
p = mod_mul(p, p, n);
if (p != n - 1 && i != s)
return 0;
}
return 1;
}
namespace dacin {
namespace Factor {
template <typename T, typename SFINAE = void> struct bigger_type {};
template <typename T> using bigger_type_t = ull;
template <typename T>
struct bigger_type<T, typename enable_if<is_integral<T>::value && is_signed<T>::value && sizeof(T) == 4>::type> {
using type = long long;
};
template <typename T>
struct bigger_type<T, typename enable_if<is_integral<T>::value && !is_signed<T>::value && sizeof(T) == 4>::type> {
using type = unsigned long long;
};
/*template<typename T> struct bigger_type<T, typename enable_if<is_integral<T>::value && is_signed<T>::value &&
sizeof(T) == 8>::type>{using type = __int128;}; template<typename T> struct bigger_type<T, typename
enable_if<is_integral<T>::value && !is_signed<T>::value && sizeof(T) == 8>::type>{using type = unsigned __int128;};*/
template <typename int_t = unsigned long long> struct Mod_Int {
static inline int_t add(int_t const &a, int_t const &b, int_t const &mod) {
int_t ret = a + b;
if (ret >= mod)
ret -= mod;
return ret;
}
static inline int_t sub(int_t const &a, int_t const &b, int_t const &mod) { return add(a, mod - b); }
static inline int_t mul(int_t const &a, int_t const &b, int_t const &mod) {
return a * static_cast<bigger_type_t<int_t>>(b) % mod;
}
static inline int_t pow(int_t const &a, int_t const &b, int_t const &mod) {
int_t ret = 1;
int_t base = a;
for (int i = 0; b >> i; ++i) {
if ((b >> i) & 1)
ret = mul(ret, base, mod);
base = mul(base, base, mod);
}
return ret;
}
};
template <typename T> bool is_prime(T x) {
static_assert(is_integral<T>::value);
if (x < T(4))
return x > T(1);
for (T i = 2; i * i <= x; ++i) {
if (x % i == 0)
return false;
}
return true;
}
template <typename T> bool miller_rabin_single(T const &x, T base) {
static_assert(is_integral<T>::value);
if (x < T(4))
return x > T(1);
if (x % 2 == 0)
return false;
base %= x;
if (base == 0)
return true;
T xm1 = x - 1;
int j = 1;
T d = xm1 / 2;
while (d % 2 == 0) { // could use __builtin_ctz
d /= 2;
++j;
}
T t = Mod_Int<T>::pow(base, d, x);
if (t == T(1) || t == T(xm1))
return true;
for (int k = 1; k < j; ++k) {
t = Mod_Int<T>::mul(t, t, x);
if (t == xm1)
return true;
if (t <= 1)
break;
}
return false;
}
template <typename T> bool miller_rabin_multi(T const &) { return true; }
template <typename T, typename... S> bool miller_rabin_multi(T const &x, T const &base, S const &... bases) {
static_assert(is_integral<T>::value);
if (!miller_rabin_single(x, base))
return false;
return miller_rabin_multi(x, bases...);
}
template <typename T> bool miller_rabin(T const &x) {
static_assert(is_integral<T>::value);
if (x < 316349281)
return miller_rabin_multi(x, T(11000544), T(31481107));
if (x < 4759123141ull)
return miller_rabin_multi(x, T(2), T(7), T(61));
return miller_rabin_multi(x, T(2), T(325), T(9375), T(28178), T(450775), T(9780504), T(1795265022));
}
template <typename T> T isqrt(T const &x) {
static_assert(is_integral<T>::value);
assert(x >= T(0));
T ret = static_cast<T>(sqrtl(x));
while (ret > 0 && ret * ret > x)
--ret;
while (x - ret * ret > 2 * ret)
++ret;
return ret;
}
template <typename T> T icbrt(T const &x) {
static_assert(is_integral<T>::value);
assert(x >= T(0));
T ret = static_cast<T>(cbrt(x));
while (ret > 0 && ret * ret * ret > x)
--ret;
while (x - ret * ret * ret > 3 * ret * (ret + 1))
++ret;
return ret;
}
vector<uint16_t> saved;
// fast prime factorization from
// https://g...content-available-to-author-only...b.com/radii/msieve
uint64_t squfof_iter_better(uint64_t const &x, uint64_t const &k, uint64_t const &it_max, uint32_t cutoff_div) {
if (__gcd((uint64_t)k, x) != 1)
return __gcd((uint64_t)k, x);
// cerr << "try: " << x << " " << k << "\n";
saved.clear();
uint64_t scaledn = k * x;
if (scaledn >> 62)
return 1;
uint32_t sqrtn = isqrt(scaledn);
uint32_t cutoff = isqrt(2 * sqrtn) / cutoff_div;
uint32_t q0 = 1;
uint32_t p1 = sqrtn;
uint32_t q1 = scaledn - p1 * p1;
if (q1 == 0) {
uint64_t factor = __gcd(x, (uint64_t)p1);
return factor == x ? 1 : factor;
}
uint32_t multiplier = 2 * k;
uint32_t coarse_cutoff = cutoff * multiplier;
// cerr << "at: " << multiplier << "\n";
uint32_t i, j;
uint32_t p0 = 0;
uint32_t sqrtq = 0;
for (i = 0; i < it_max; ++i) {
uint32_t q, bits, tmp;
tmp = sqrtn + p1 - q1;
q = 1;
if (tmp >= q1)
q += tmp / q1;
p0 = q * q1 - p1;
q0 = q0 + (p1 - p0) * q;
if (q1 < coarse_cutoff) {
tmp = q1 / __gcd(q1, multiplier);
if (tmp < cutoff) {
saved.push_back((uint16_t)tmp);
}
}
bits = 0;
tmp = q0;
while (!(tmp & 1)) {
bits++;
tmp >>= 1;
}
if (!(bits & 1) && ((tmp & 7) == 1)) {
sqrtq = (uint32_t)isqrt(q0);
if (sqrtq * sqrtq == q0) {
for (j = 0; j < saved.size(); ++j) {
if (saved[j] == sqrtq)
break;
}
if (j == saved.size())
break;
// else cerr << "skip " << i << "\n";;
}
}
tmp = sqrtn + p0 - q0;
q = 1;
if (tmp >= q0)
q += tmp / q0;
p1 = q * q0 - p0;
q1 = q1 + (p0 - p1) * q;
if (q0 < coarse_cutoff) {
tmp = q0 / __gcd(q0, multiplier);
if (tmp < cutoff) {
saved.push_back((uint16_t)tmp);
}
}
}
if (sqrtq == 1) {
return 1;
}
if (i == it_max) {
return 1;
}
q0 = sqrtq;
p1 = p0 + sqrtq * ((sqrtn - p0) / sqrtq);
q1 = (scaledn - (uint64_t)p1 * (uint64_t)p1) / (uint64_t)q0;
for (j = 0; j < it_max; ++j) {
uint32_t q, tmp;
tmp = sqrtn + p1 - q1;
q = 1;
if (tmp >= q1)
q += tmp / q1;
p0 = q * q1 - p1;
q0 = q0 + (p1 - p0) * q;
if (p0 == p1) {
q0 = q1;
break;
}
tmp = sqrtn + p0 - q0;
q = 1;
if (tmp >= q0)
q += tmp / q0;
p1 = q * q0 - p0;
q1 = q1 + (p0 - p1) * q;
if (p0 == p1)
break;
}
if (j == it_max) {
cerr << "RNG\n";
return 1;
} // random fail
uint64_t factor = __gcd((uint64_t)q0, x);
if (factor == x)
factor = 1;
return factor;
}
uint64_t squfof(uint64_t const &x) {
static array<uint32_t, 16> multipliers{
1, 3, 5, 7, 11, 3 * 5, 3 * 7, 3 * 11,
5 * 7, 5 * 11, 7 * 11, 3 * 5 * 7, 3 * 5 * 11, 3 * 7 * 11, 5 * 7 * 11, 3 * 5 * 7 * 11};
uint64_t cbrt_x = icbrt(x);
if (cbrt_x * cbrt_x * cbrt_x == x)
return cbrt_x;
uint32_t iter_lim = isqrt(isqrt(x)) + 10;
// uint32_t iter_lim = 300;
for (uint32_t iter_fact = 1; iter_fact < 20000; iter_fact *= 4) {
for (uint32_t const &k : multipliers) {
if (numeric_limits<uint64_t>::max() / k <= x)
continue; // would overflow
uint32_t const it_max = iter_fact * iter_lim;
uint64_t factor = squfof_iter_better(x, k, it_max, 1);
if (factor == 1 || factor == x)
continue;
return factor;
}
}
cerr << "failed to factor: " << x << "\n";
assert(0);
return 1;
}
template <typename T> vector<T> factorize(T x) {
static_assert(is_integral<T>::value);
vector<T> ret;
const uint32_t trial_limit = 1000;
auto trial = [&](int i) {
while (x % i == 0) {
x /= i;
ret.push_back(i);
}
};
trial(2);
trial(3);
for (uint32_t i = 5, j = 2; i < trial_limit && i * i <= x; i += j, j = 6 - j) {
trial(i);
}
if (x > 1) {
static stack<T> s;
s.push(x);
while (!s.empty()) {
x = s.top();
s.pop();
if (!miller_rabin(x)) {
T factor = squfof(x);
if (factor == 1 || factor == x) {
assert(0);
return ret;
}
s.push(factor);
s.push(x / factor);
} else {
ret.push_back(x);
}
}
}
sort(ret.begin(), ret.end());
return ret;
}
} // namespace Factor
} // namespace dacin
const int maxp = 1e6, maxv = 25;
namespace cancer {
ll pollard(ll n) {
static ll seq[maxp];
while (1) {
ll x = rand() % n, y = x, c = rand() % n;
ll *px = seq, *py = seq, tim = 0, prd = 1;
while (1) {
*py++ = y = mod_add(mod_mul(y, y, n), c, n);
*py++ = y = mod_add(mod_mul(y, y, n), c, n);
if ((x = *px++) == y)
break;
ll tmp = prd;
prd = mod_mul(prd, abs(y - x), n);
if (!prd)
return gcd(tmp, n);
if ((++tim) == maxv) {
if ((prd = gcd(prd, n)) > 1 && prd < n)
return prd;
tim = 0;
}
}
if (tim && (prd = gcd(prd, n)) > 1 && prd < n)
return prd;
}
}
} // namespace cancer
namespace kactl {
ull pollard(ull n) {
auto f = [n](ull x) { return (mod_mul(x, x, n) + 1) % n; };
if (!(n & 1))
return 2;
for (ull i = 2;; i++) {
ull x = i, y = f(x), p;
while ((p = gcd(n + y - x, n)) == 1)
x = f(x), y = f(f(y));
if (p != n)
return p;
}
}
} // namespace kactl
namespace brent {
ll pollard(ll n) {
if (!(n & 1))
return 2;
if (n == 25)
return 5;
auto f = [n](ull x) { return mod_add(mod_mul(x, x, n), 1, n); };
for (ll i = 2;; i = rand() % n) {
ll power = 1, lam = 1;
ll x = i, y = f(x);
ll tim = 0, prd = 1;
while (1) {
if (power == lam) {
x = y;
power *= 2;
lam = 0;
}
y = f(y);
lam++;
if (x == y)
break;
prd = mod_mul(prd, n + y - x, n);
if (!prd) {
return gcd(n + y - x, n);
}
if ((++tim) == maxv) {
if ((prd = gcd(prd, n)) > 1 && prd < n)
return prd;
tim = 0;
}
}
if ((prd = gcd(prd, n)) > 1 && prd < n)
return prd;
}
}
} // namespace brent
namespace china {
ull n, niv_n;
void setn(ull n_) {
n = n_;
niv_n = 1;
ull x = n;
for (int i = 1; i <= 62; i++) {
niv_n *= x;
x *= x;
}
}
ull rho(ull seed, ull n, ull inc) {
static const int step = 1 << 9;
setn(n);
auto f = [n](ull x, ull inc) { return mod_mul(x, x, n) + inc; };
auto sub = [&](ull x, ull y) { return x > y ? x - y : y - x; };
ull y = f(seed, inc), a = f(seed, inc);
for (int l = 1;; l <<= 1) {
ull x = y;
for (int i = 1; i <= l; i++)
y = f(y, inc);
for (int k = 0; k < l; k += step) {
int d = min(step, l - k);
ull g = seed, y0 = y;
for (int i = 1; i <= d; i++) {
y = f(y, inc);
g = mod_mul(g, sub(x, y), n);
}
g = gcd(g, n);
if (g == 1)
continue;
if (g != n)
return g;
ull y = y0;
while (gcd(sub(x, y), n) == 1)
y = f(y, inc);
return gcd(sub(x, y), n) % n;
}
}
return 0;
}
int const num_tries = 10;
ull pollard(ull x) {
if (x % 2 == 0)
return 2;
if (x % 3 == 0)
return 3;
for (ull i = 2; i < num_tries; i++) {
ull ans = rho(rand(), x, i);
if (ans != 0 and ans != x)
return ans;
}
return 0;
}
} // namespace china
namespace pajene {
ull pollard(ull n) {
auto f = [n](ull x) { return mod_mul(x, x, n) + 1; };
if (!(n & 1))
return 2;
ull x = 0, y = 0, tim = 0, prd = 1, i = 1, tmp;
for (; prd; y = f(f(y)), x = f(x)) {
if (x == y || ++tim == 40) {
tim = 0;
if ((prd = gcd(prd, n)) > 1)
return prd;
while (x == y)
x = ++i, y = f(x);
}
tmp = prd, prd = mod_mul(prd, n + y - x, n);
}
return gcd(tmp, n);
}
} // namespace pajene
namespace newkactl {
int maxv = 40;
ull pollard(ull n) {
auto f = [n](ull x) { return mod_mul(x, x, n) + 1; };
if (!(n & 1))
return 2;
for (ull i = 2;; i = rand() % n) {
ull x = i, y = f(x), tim = 0, prd = 1;
while ((x = f(x)) != (y = f(f(y)))) {
if (!(prd = mod_mul(prd, n + y - x, n)))
return gcd(n + y - x, n);
if ((++tim) == maxv) {
prd = gcd(prd, n), tim = 0;
if (prd > 1)
return prd;
}
}
if ((prd = gcd(prd, n)) > 1)
return prd;
}
}
} // namespace newkactl
int ptot, pr[maxp], d[maxp];
vector<ull> factor(ull n, const string &version) {
if (n == 1)
return {};
if (isPrime(n))
return {n};
ull x = 0;
if (version == "cancer") {
x = cancer::pollard(n);
} else if (version == "pajene") {
x = pajene::pollard(n);
} else if (version == "newkactl") {
x = newkactl::pollard(n);
} else if (version == "brent") {
x = brent::pollard(n);
} else if (version == "china") {
x = china::pollard(n);
} else {
x = kactl::pollard(n);
}
auto l = factor(x, version), r = factor(n / x, version);
l.insert(l.end(), all(r));
return l;
}
void sieve() {
for (int p = 2; p < maxp; p++) {
if (!d[p])
pr[ptot++] = d[p] = p;
for (int j = 0, k; (k = p * pr[j]) < maxp; ++j) {
d[k] = pr[j];
if (d[p] == pr[j])
break;
}
}
}
const int ITERS = 1e2;
int main() {
sieve();
vector<ull> primes;
const ull MN_SIZE = 1e9 - 1e5;
const ull MX_SIZE = 1e9;
for (int i = MN_SIZE; i < MX_SIZE; i++) {
if (isPrime(i)) {
primes.push_back(i);
}
}
vector<ull> vals;
for (int i = 0; i < ITERS; i++)
vals.push_back(uni(rng));
vector<ull> spvals;
for (int i = 0; i < ITERS; i++) {
ull a = primes[uni(rng) % primes.size()];
ull b = primes[uni(rng) % primes.size()];
spvals.push_back(a * b);
}
vector<ull> seq;
for (int i = 0; i < ITERS; i++) {
seq.push_back(i + 2);
}
vals = spvals;
// vals = seq;
{
gcd_count = 0;
mul_cnt = 0;
timeit x("pajene rho");
int ans = 0;
for (int i = 0; i < ITERS; i++) {
ull x = vals[i];
// cout << x << endl;
auto res = factor(x, "pajene");
for (auto x : res)
ans += x;
}
cout << ans << endl;
cout << gcd_count << ' ' << mul_cnt << endl;
}
// {
// cout << endl;
// gcd_count = 0;
// mul_cnt = 0;
// timeit x("brent rho");
// int ans = 0;
// for (int i = 0; i < ITERS; i++) {
// ull x = vals[i];
// // cout << x << endl;
// auto res = factor(x, "brent");
// ans += res[0];
// }
// cout << ans << endl;
// cout << gcd_count << ' ' << mul_cnt << endl;
// }
// {
// cout << endl;
// gcd_count = 0;
// mul_cnt = 0;
// timeit x("new kactl rho");
// int ans = 0;
// for (int i = 0; i < ITERS; i++) {
// ull x = vals[i];
// // cout << x << endl;
// auto res = factor(x, "newkactl");
// for (auto x : res)
// ans += x;
// }
// cout << ans << endl;
// cout << gcd_count << ' ' << mul_cnt << endl;
// }
// {
// gcd_count = 0;
// timeit x("cancer rho");
// int ans = 0;
// for (int i = 0; i < ITERS; i++) {
// ull x = vals[i];
// auto res = factor(x, "cancer");
// for (auto x : res)
// ans += x;
// }
// cout << ans << endl;
// cout << gcd_count << endl;
// }
// {
// gcd_count = 0;
// timeit x("new kactl cache rho");
// int ans = 0;
// for (int i = 0; i < ITERS; i++) {
// ull x = vals[i];
// auto res = factor(x, "newkactlcache");
// for (auto x : res)
// ans += x;
// }
// cout << ans << endl;
// cout << gcd_count << endl;
// }
// {
// gcd_count = 0;
// timeit x("china rho");
// int ans = 0;
// for (int i = 0; i < ITERS; i++) {
// ull x = vals[i];
// auto res = factor(x, "china");
// for (auto x : res)
// ans += x;
// }
// cout << ans << endl;
// cout << gcd_count << endl;
// }
{
cout << endl;
gcd_count = 0;
mul_cnt = 0;
timeit x("kactl rho");
int ans = 0;
for (int i = 0; i < ITERS; i++) {
ull x = vals[i];
auto res = factor(x, "kactl");
for (auto x : res)
ans += x;
}
cout << ans << endl;
cout << gcd_count << ' ' << mul_cnt << endl;
}
// {
// cout << endl;
// timeit x("dacin factorize");
// int ans = 0;
// for (int i = 0; i < ITERS; i++) {
// ull x = vals[i];
// auto res = dacin::Factor::factorize(x);
// for (auto x : res)
// ans += x;
// }
// cout << ans << endl;
// }
}