#include using namespace std; using u64 = uint64_t; using u128 = __uint128_t; static string to_string_u128(u128 x) { if (!x) return "0"; char s[64]; int n = 0; while (x) { s[n++] = char('0' + x % 10); x /= 10; } reverse(s, s + n); return string(s, s + n); } static u128 parse_u128(const string& s) { u128 x = 0; for (char c : s) x = x * 10 + (c - '0'); return x; } static u64 isqrt_u128(u128 n) { u64 x = (u64)sqrt((long double)n); while ((u128)x * x > n) --x; while ((u128)(x + 1) * (x + 1) <= n) ++x; return x; } /* * Montgomery arithmetic modulo an odd integer below 2^127. * Values are represented modulo R = 2^128. */ struct Mont128 { u128 mod, ninv, r1, r2; static inline u128 mul_hi(u128 x, u128 y) { u64 x0 = (u64)x, x1 = (u64)(x >> 64); u64 y0 = (u64)y, y1 = (u64)(y >> 64); u128 z11 = (u128)x1 * y1; u128 z10 = (u128)x1 * y0; u128 z01 = (u128)x0 * y1; u128 z00 = (u128)x0 * y0; u128 mid = (z00 >> 64) + (u64)z10 + (u64)z01; return z11 + (z10 >> 64) + (z01 >> 64) + (mid >> 64); } explicit Mont128(u128 n) : mod(n) { u128 x = n; for (int bits = 1; bits < 128; bits <<= 1) { x *= 2 - x * n; } ninv = -x; r1 = (-n) % n; r2 = r1; for (int i = 0; i < 128; ++i) { r2 <<= 1; if (r2 >= n) r2 -= n; } } inline u128 mul(u128 x, u128 y) const { u128 lo = x * y; u128 m = lo * ninv; u128 t = mul_hi(x, y) + mul_hi(m, mod) + (lo != 0); return t >= mod ? t - mod : t; } inline u128 init(u128 x) const { return mul(x % mod, r2); } inline u128 norm(u128 x) const { return mul(x, 1); } inline u128 add(u128 x, u128 y) const { u128 z = x + y; if (z >= mod) z -= mod; return z; } inline u128 pow_mont(u128 x, u128 e) const { u128 a = r1; while (e) { if (e & 1) a = mul(a, x); x = mul(x, x); e >>= 1; } return a; } inline u128 pow(u128 x, u128 e) const { return norm(pow_mont(init(x), e)); } }; static u128 gcd128(u128 a, u128 b) { while (b) { u128 r = a % b; a = b; b = r; } return a; } static bool is_prime128(u128 n) { if (n < 2) return false; static constexpr uint32_t SMALL[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37 }; for (uint32_t p : SMALL) { if (n == p) return true; if (n % p == 0) return false; } Mont128 md(n); u128 d = n - 1; int s = 0; while (!(d & 1)) { d >>= 1; ++s; } auto witness = [&](u128 a) { if (a % n == 0) return false; u128 x = md.pow_mont(md.init(a), d); if (x == md.r1 || x == md.mod - md.r1) return false; for (int r = 1; r < s; ++r) { x = md.mul(x, x); if (x == md.mod - md.r1) return false; } return true; }; // Deterministic for n < 3.317... * 10^24. static constexpr uint32_t BASES[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41 }; for (uint32_t a : BASES) { if (witness(a)) return false; } return true; } static inline u64 mul_mod64(u64 a, u64 b, u64 mod) { return (u128)a * b % mod; } static u64 pow_mod64(u64 a, u64 e, u64 mod) { u64 r = 1; while (e) { if (e & 1) r = mul_mod64(r, a, mod); a = mul_mod64(a, a, mod); e >>= 1; } return r; } /* Brent–Pollard rho for 64-bit recursive cofactors. */ static u64 rho64(u64 n) { if (n % 2 == 0) return 2; auto rng = []() -> u64 { static u64 x = 0x9e3779b97f4a7c15ULL ^ (u64)chrono::high_resolution_clock::now() .time_since_epoch().count(); x ^= x << 7; x ^= x >> 9; return x; }; while (true) { u64 y = rng() % (n - 1) + 1; u64 c = rng() % (n - 1) + 1; constexpr u64 M = 128; u64 g = 1, r = 1, q = 1; u64 x = 0, ys = 0; auto f = [&](u64 v) { return (mul_mod64(v, v, n) + c) % n; }; while (g == 1) { x = y; for (u64 i = 0; i < r; ++i) y = f(y); for (u64 k = 0; k < r && g == 1; k += M) { ys = y; u64 lim = min(M, r - k); for (u64 i = 0; i < lim; ++i) { y = f(y); u64 d = x > y ? x - y : y - x; q = mul_mod64(q, d, n); } g = std::gcd(q, n); } r <<= 1; } if (g == n) { do { ys = f(ys); u64 d = x > ys ? x - ys : ys - x; g = std::gcd(d, n); } while (g == 1); } if (g != n) return g; } } /* Tonelli–Shanks modulo a small prime. */ static u64 tonelli(uint32_t n, uint32_t p) { if (p == 2) return n & 1; if (n == 0) return 0; if (p % 4 == 3) return pow_mod64(n, (p + 1) / 4, p); uint32_t q = p - 1; uint32_t s = 0; while ((q & 1) == 0) { q >>= 1; ++s; } uint32_t z = 2; while (pow_mod64(z, (p - 1) / 2, p) != p - 1) ++z; u64 c = pow_mod64(z, q, p); u64 x = pow_mod64(n, (q + 1) / 2, p); u64 t = pow_mod64(n, q, p); uint32_t m = s; while (t != 1) { uint32_t i = 1; u64 tt = mul_mod64(t, t, p); while (tt != 1) { tt = mul_mod64(tt, tt, p); ++i; } u64 b = pow_mod64(c, 1ULL << (m - i - 1), p); x = mul_mod64(x, b, p); c = mul_mod64(b, b, p); t = mul_mod64(t, c, p); m = i; } return x; } struct FBPrime { uint32_t p, r1, r2; uint16_t lg; }; struct Atom { u64 x, q; }; struct Relation { vector parity; array a; uint8_t cnt; }; struct Partial { vector parity; Atom a; }; static vector primes_upto(int bound) { vector is_prime(bound + 1, true); is_prime[0] = is_prime[1] = false; vector primes; for (int i = 2; i <= bound; ++i) { if (!is_prime[i]) continue; primes.push_back(i); if ((int64_t)i * i <= bound) { for (int j = i * i; j <= bound; j += i) { is_prime[j] = false; } } } return primes; } /* * Quadratic sieve specialized for 65–80-bit integers. * * Q(x) = (ceil(sqrt(kN)) + x)^2 - kN. * Within the scanned range Q(x) fits in uint64_t, so almost all sieve and * trial-division work uses native 64-bit arithmetic. */ static u128 quadratic_sieve_factor( u128 n, int factor_bound = 7000, int extra_relations = 48, u64 max_base = 3500000 ) { constexpr int BLOCK = 1 << 15; vector primes = primes_upto(factor_bound); static constexpr uint32_t MULTIPLIERS[] = { 1, 3, 5, 7, 11, 13, 15, 17, 19, 21, 23, 29, 31, 33, 35, 37, 39, 41, 43, 47 }; uint32_t best_k = 1; long double best_score = -1e100L; for (uint32_t k : MULTIPLIERS) { u128 g = gcd128(n, k); if (g > 1 && g < n) return g; long double score = -0.5L * log((long double)k); for (uint32_t p : primes) { if (p > 100) break; u64 a = (u64)((n % p) * (k % p) % p); if (a == 0) { score += log((long double)p) / (p - 1); } else if ( p == 2 || pow_mod64(a, (p - 1) / 2, p) == 1 ) { score += 2 * log((long double)p) / (p - 1); } } if (score > best_score) { best_score = score; best_k = k; } } u128 kn = n * best_k; u64 m = isqrt_u128(kn); if ((u128)m * m < kn) ++m; if ((u128)m * m == kn) { u128 g = gcd128(m, n); if (g > 1 && g < n) return g; best_k = 1; kn = n; m = isqrt_u128(n); if ((u128)m * m < n) ++m; } vector factor_base; factor_base.reserve(primes.size() / 2 + 8); for (uint32_t p : primes) { if (n % p == 0) return p; u64 a = (u64)(kn % p); if (p == 2) { uint32_t y = a & 1; uint32_t mm = m & 1; uint32_t r = (y + 2 - mm) & 1; factor_base.push_back({p, r, r, 64}); continue; } u64 legendre = pow_mod64(a, (p - 1) / 2, p); if (legendre != 1 && a != 0) continue; uint32_t y = (uint32_t)tonelli((uint32_t)a, p); uint32_t mm = m % p; uint32_t r1 = (y + p - mm) % p; uint32_t r2 = ((y ? p - y : 0) + p - mm) % p; factor_base.push_back({ p, r1, r2, (uint16_t)llround(log2((long double)p) * 64) }); } const int columns = (int)factor_base.size(); const int parity_words = (columns + 63) >> 6; vector relations; relations.reserve(columns + extra_relations + 8); unordered_map partials; partials.reserve((columns + extra_relations) * 8); vector sieve(BLOCK); const u64 large_prime_bound = (u64)factor_bound * factor_bound; for ( u64 base = 0; relations.size() < (size_t)(columns + extra_relations); base += BLOCK ) { fill(sieve.begin(), sieve.end(), 0); for (const FBPrime& f : factor_base) { uint32_t p = f.p; uint32_t base_mod = base % p; uint32_t start1 = (f.r1 + p - base_mod) % p; for (uint32_t i = start1; i < BLOCK; i += p) { sieve[i] += f.lg; } if (f.r2 != f.r1) { uint32_t start2 = (f.r2 + p - base_mod) % p; for (uint32_t i = start2; i < BLOCK; i += p) { sieve[i] += f.lg; } } } for ( uint32_t i = 0; i < BLOCK && relations.size() < (size_t)(columns + extra_relations); ++i ) { u64 x = base + i; u128 qq = (u128)(m + x) * (m + x) - kn; if ( qq == 0 || qq > numeric_limits::max() ) { continue; } u64 q = (u64)qq; int bits = 64 - __builtin_clzll(q); // Allows repeated small prime factors not represented // repeatedly in the logarithmic sieve. if ((int)sieve[i] + 14 * 64 < bits * 64) { continue; } u64 rem = q; vector parity(parity_words); for (int j = 0; j < columns; ++j) { uint32_t p = factor_base[j].p; int odd = 0; while (rem % p == 0) { rem /= p; odd ^= 1; } if (odd) { parity[j >> 6] ^= 1ULL << (j & 63); } if (rem == 1) break; } if (rem == 1) { Relation relation; relation.parity = move(parity); relation.a[0] = {x, q}; relation.cnt = 1; relations.push_back(move(relation)); } else if (rem <= large_prime_bound) { /* * Every prime <= factor_bound that can divide Q(x) * belongs to the factor base. Therefore a remaining * value <= B^2 must be prime. */ auto it = partials.find(rem); if (it == partials.end()) { partials.emplace( rem, Partial{move(parity), {x, q}} ); } else { Relation relation; relation.parity = move(parity); for (int w = 0; w < parity_words; ++w) { relation.parity[w] ^= it->second.parity[w]; } relation.a[0] = it->second.a; relation.a[1] = {x, q}; relation.cnt = 2; relations.push_back(move(relation)); partials.erase(it); } } } if ( base > max_base && relations.size() < (size_t)(columns + extra_relations) ) { break; } } if (relations.size() <= (size_t)columns) { return 0; } const int relation_count = (int)relations.size(); const int combination_words = (relation_count + 63) >> 6; struct BasisRow { vector parity; vector combination; bool used = false; }; vector basis(columns); vector> dependencies; dependencies.reserve(extra_relations); for (int i = 0; i < relation_count; ++i) { vector parity = relations[i].parity; vector combination(combination_words); combination[i >> 6] |= 1ULL << (i & 63); bool inserted = false; for (int column = columns - 1; column >= 0; --column) { if ( ((parity[column >> 6] >> (column & 63)) & 1ULL) == 0 ) { continue; } if (!basis[column].used) { basis[column].used = true; basis[column].parity = move(parity); basis[column].combination = move(combination); inserted = true; break; } for (int w = 0; w < parity_words; ++w) { parity[w] ^= basis[column].parity[w]; } for (int w = 0; w < combination_words; ++w) { combination[w] ^= basis[column].combination[w]; } } if (!inserted) { bool zero = true; for (u64 x : parity) { if (x) { zero = false; break; } } if (zero) { dependencies.push_back(move(combination)); } } } Mont128 md(n); for (const vector& dependency : dependencies) { vector exponents(columns); unordered_map large_exponents; large_exponents.reserve(16); u128 X = md.r1; for (int r = 0; r < relation_count; ++r) { if ( ((dependency[r >> 6] >> (r & 63)) & 1ULL) == 0 ) { continue; } for (int ai = 0; ai < relations[r].cnt; ++ai) { auto [x, q] = relations[r].a[ai]; X = md.mul( X, md.init((u128)(m + x) % n) ); u64 rem = q; for (int j = 0; j < columns; ++j) { uint32_t p = factor_base[j].p; while (rem % p == 0) { rem /= p; ++exponents[j]; } if (rem == 1) break; } if (rem > 1) { ++large_exponents[rem]; } } } u128 Y = md.r1; bool valid = true; for (int j = 0; j < columns; ++j) { if (exponents[j] & 1) { valid = false; break; } if (exponents[j]) { Y = md.mul( Y, md.pow_mont( md.init(factor_base[j].p), exponents[j] / 2 ) ); } } if (!valid) continue; for (auto [p, e] : large_exponents) { if (e & 1) { valid = false; break; } Y = md.mul( Y, md.pow_mont(md.init(p), e / 2) ); } if (!valid) continue; u128 xn = md.norm(X); u128 yn = md.norm(Y); u128 difference = xn > yn ? xn - yn : yn - xn; u128 divisor = gcd128(difference, n); if (divisor > 1 && divisor < n) { return divisor; } u128 sum = xn + yn; if (sum >= n) sum -= n; divisor = gcd128(sum, n); if (divisor > 1 && divisor < n) { return divisor; } } return 0; } /* Slow-path fallback for a QS failure. */ static u128 rho128(u128 n) { if (n % 2 == 0) return 2; auto rng = []() -> u64 { static u64 x = 0x243f6a8885a308d3ULL ^ (u64)chrono::high_resolution_clock::now() .time_since_epoch().count(); x ^= x << 7; x ^= x >> 9; return x; }; Mont128 md(n); auto random_mod = [&]() { return (((u128)rng() << 64) | rng()) % n; }; while (true) { u128 y = md.init(random_mod()); u128 c = md.init(random_mod() + 1); u128 x = 0, ys = 0; constexpr u64 M = 256; u64 r = 1; u128 g = 1; auto f = [&](u128 v) { return md.add(md.mul(v, v), c); }; while (g == 1) { x = y; for (u64 i = 0; i < r; ++i) y = f(y); for (u64 k = 0; k < r && g == 1; k += M) { ys = y; u128 q = md.r1; u64 lim = min(M, r - k); for (u64 i = 0; i < lim; ++i) { y = f(y); u128 d = x > y ? x - y : y - x; q = md.mul(q, d); } g = gcd128(q, n); } r <<= 1; } if (g == n) { do { ys = f(ys); u128 d = x > ys ? x - ys : ys - x; g = gcd128(d, n); } while (g == 1); } if (g != n) return g; } } static void factor_rec(u128 n, vector& factors) { if (n == 1) return; static constexpr uint32_t SMALL[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97 }; for (uint32_t p : SMALL) { if (n % p == 0) { factors.push_back(p); factor_rec(n / p, factors); return; } } if (is_prime128(n)) { factors.push_back(n); return; } u64 square_root = isqrt_u128(n); if ((u128)square_root * square_root == n) { factor_rec(square_root, factors); factor_rec(square_root, factors); return; } u128 divisor; if (n <= numeric_limits::max()) { divisor = rho64((u64)n); } else { divisor = quadratic_sieve_factor( n, 7000, 48, 3500000 ); if (divisor == 0 || divisor == n) { divisor = quadratic_sieve_factor( n, 10000, 64, 5000000 ); } if (divisor == 0 || divisor == n) { divisor = rho128(n); } } factor_rec(divisor, factors); factor_rec(n / divisor, factors); } static inline u128 pow_cap( u128 a, int exponent, u128 cap ) { u128 result = 1; for (int i = 0; i < exponent; ++i) { if (a && result > cap / a) return cap + 1; result *= a; } return result; } /* * Sum over [l, l+w). * Only e=1,2,3,4 are used. */ static u128 power_sum_small(int e, u128 l, u128 w) { if (e == 1) { return l * w + w * (w - 1) / 2; } if (e == 2) { return l * w * (l + w - 1) + w * (w - 1) / 2 * (2 * w - 1) / 3; } if (e == 3) { return w * (2 * l + w - 1) / 2 * l * (l + w - 1) + w * w * (w - 1) / 2 * (2 * l + w - 1) / 2; } if (e == 4) { return l * w * (l + w - 1) * (l * (l + w - 1) + w * (w - 1)) + w * (w - 1) / 2 * (2 * w - 1) / 3 * (3 * w * (w - 1) - 1) / 5; } abort(); } using Solution = tuple; static vector divisors_limited( const map& factorization, u128 limit ) { vector> factors( factorization.begin(), factorization.end() ); vector divisors; auto dfs = [&](auto&& self, int index, u128 value) -> void { if (index == (int)factors.size()) { divisors.push_back(value); return; } auto [prime, exponent] = factors[index]; for (int e = 0; e <= exponent; ++e) { self(self, index + 1, value); if ( e == exponent || value > limit / prime ) { break; } value *= prime; } }; dfs(dfs, 0, 1); return divisors; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); string input; cin >> input; u128 N = parse_u128(input); vector prime_factors; factor_rec(N, prime_factors); sort(prime_factors.begin(), prime_factors.end()); map factorization; for (u128 p : prime_factors) { ++factorization[p]; } vector answers; /* * E = 1: * * 2N = W(2L+W-1). * The two factors have opposite parity. */ { map factors_2N = factorization; ++factors_2N[2]; u128 twoN = 2 * N; u64 limit = isqrt_u128(twoN - 1); vector widths = divisors_limited(factors_2N, limit); for (u128 width : widths) { u128 other = twoN / width; if ((width & 1) == (other & 1)) { continue; } u128 left = (other - width + 1) / 2; answers.emplace_back( 1, left, left + width - 1 ); } } /* * For every L,W: * * W | 6*S(2,L,L+W-1) * W | 2*S(3,L,L+W-1) * W | 30*S(4,L,L+W-1) * * Therefore, for a solution, W divides D[E]*N. */ static constexpr int DENOMINATOR[5] = { 0, 0, 6, 2, 30 }; for (int exponent = 2; exponent <= 4; ++exponent) { map width_factorization = factorization; int d = DENOMINATOR[exponent]; for (int p = 2; p * p <= d; ++p) { while (d % p == 0) { ++width_factorization[p]; d /= p; } } if (d > 1) ++width_factorization[d]; u64 upper = 1; while ( power_sum_small(exponent, 1, upper) <= N ) { upper <<= 1; } u64 lower = 0; while (lower + 1 < upper) { u64 middle = (lower + upper) / 2; if ( power_sum_small( exponent, 1, middle ) <= N ) { lower = middle; } else { upper = middle; } } vector widths = divisors_limited( width_factorization, lower ); sort(widths.begin(), widths.end()); u64 maximum_left = 1; while ( pow_cap(maximum_left, exponent, N) <= N ) { maximum_left <<= 1; } for (u128 width : widths) { u64 lo = 1; u64 hi = maximum_left; while (lo < hi) { u64 middle = lo + (hi - lo) / 2; if ( power_sum_small( exponent, middle, width ) >= N ) { hi = middle; } else { lo = middle + 1; } } if ( power_sum_small( exponent, lo, width ) == N ) { answers.emplace_back( exponent, lo, (u128)lo + width - 1 ); } } } /* * E >= 5: * sum of all running times is dominated by N^(1/5). */ int maximum_exponent = 0; for (u128 x = N; x >= 2; x >>= 1) { ++maximum_exponent; } for ( int exponent = 5; exponent <= maximum_exponent; ++exponent ) { vector powers(1, 0); for (u64 i = 1;; ++i) { u128 value = pow_cap(i, exponent, N); if (value > N) break; powers.push_back(value); } size_t right = 1; u128 sum = 0; for ( size_t left = 1; left < powers.size(); ++left ) { if (right < left) { right = left; sum = 0; } while ( right < powers.size() && sum + powers[right] <= N ) { sum += powers[right]; ++right; } if (sum == N) { answers.emplace_back( exponent, left, right - 1 ); } if (right > left) { sum -= powers[left]; } } } sort(answers.begin(), answers.end()); cout << answers.size() << '\n'; for (auto [e, l, r] : answers) { cout << e << ' ' << to_string_u128(l) << ' ' << to_string_u128(r) << '\n'; } }