#include #include #define rep(i,n) for(int i=0;i vi; typedef vector vl; typedef vector> vvi; typedef vector> vvl; typedef long double ld; typedef pair P; template ostream& operator<<(ostream& os, const static_modint& a) {os << a.val(); return os;} template ostream& operator<<(ostream& os, const dynamic_modint& a) {os << a.val(); return os;} template istream& operator>>(istream& is, static_modint& a) {long long x; is >> x; a = x; return is;} template istream& operator>>(istream& is, dynamic_modint& a) {long long x; is >> x; a = x; return is;} template istream& operator>>(istream& is, vector& v){int n = v.size(); assert(n > 0); rep(i, n) is >> v[i]; return is;} template ostream& operator<<(ostream& os, const pair& p){os << p.first << ' ' << p.second; return os;} template ostream& operator<<(ostream& os, const vector& v){int n = v.size(); rep(i, n) os << v[i] << (i == n - 1 ? "\n" : " "); return os;} template ostream& operator<<(ostream& os, const vector>& v){int n = v.size(); rep(i, n) os << v[i] << (i == n - 1 ? "\n" : ""); return os;} template ostream& operator<<(ostream& os, const set& se){for(T x : se) os << x << " "; os << "\n"; return os;} template ostream& operator<<(ostream& os, const unordered_set& se){for(T x : se) os << x << " "; os << "\n"; return os;} template ostream& operator<<(ostream& os, const atcoder::segtree& seg){int n = seg.max_right(0, [](S){return true;}); rep(i, n) os << seg.get(i) << (i == n - 1 ? "\n" : " "); return os;} template ostream& operator<<(ostream& os, const atcoder::lazy_segtree& seg){int n = seg.max_right(0, [](S){return true;}); rep(i, n) os << seg.get(i) << (i == n - 1 ? "\n" : " "); return os;} template void chmin(T& a, T b){a = min(a, b);} template void chmax(T& a, T b){a = max(a, b);} // Start 14:59 // Fermat's little theorem and Euler's theorem //(I) N = 0 mod B // M^L = 0 (M = 0 and L > 0) // M^L != 0 (M != 0 or(M = 0 and L = 0)) // N^(M^L) = 1 (M = 0 and L > 0) // N^(M^L) = 0 (M != 0 or(M = 0 and L = 0)) //(II) B = 1 // ans = 1 //(III) otherwise // a^(phi(B)) = 1 mod(B) // a^(phi(phi(B))) = 1 mod(phi(B)) // Start Implementation 15:15 // 15:41 Submission -> WA // int -> long long // 15:41 Submission -> WA // Euler's theorem is ng! a and B are now always coprime!! // regularity? // a_i = n^i mod B // at most B-length repetition // the length L is always divides B-1 ? <- False // B = _Prod p_i e_i // CRT? <- ( ; ; ) // the length L is always divides phi(B) ? <- ? // montgomery modint (MOD < 2^62, MOD is odd) struct MontgomeryModInt64 { using mint = MontgomeryModInt64; using u64 = uint64_t; using u128 = __uint128_t; // static menber static u64 MOD; static u64 INV_MOD; // INV_MOD * MOD ≡ 1 (mod 2^64) static u64 T128; // 2^128 (mod MOD) // inner value u64 val; // constructor MontgomeryModInt64() : val(0) { } MontgomeryModInt64(long long v) : val(reduce((u128(v) + MOD) * T128)) { } u64 get() const { u64 res = reduce(val); return res >= MOD ? res - MOD : res; } // mod getter and setter static u64 get_mod() { return MOD; } static void set_mod(u64 mod) { assert(mod < (1LL << 62)); assert((mod & 1)); MOD = mod; T128 = -u128(mod) % mod; INV_MOD = get_inv_mod(); } static u64 get_inv_mod() { u64 res = MOD; for (int i = 0; i < 5; ++i) res *= 2 - MOD * res; return res; } static u64 reduce(const u128 &v) { return (v + u128(u64(v) * u64(-INV_MOD)) * MOD) >> 64; } // arithmetic operators mint operator - () const { return mint() - mint(*this); } mint operator + (const mint &r) const { return mint(*this) += r; } mint operator - (const mint &r) const { return mint(*this) -= r; } mint operator * (const mint &r) const { return mint(*this) *= r; } mint operator / (const mint &r) const { return mint(*this) /= r; } mint& operator += (const mint &r) { if ((val += r.val) >= 2 * MOD) val -= 2 * MOD; return *this; } mint& operator -= (const mint &r) { if ((val += 2 * MOD - r.val) >= 2 * MOD) val -= 2 * MOD; return *this; } mint& operator *= (const mint &r) { val = reduce(u128(val) * r.val); return *this; } mint& operator /= (const mint &r) { *this *= r.inv(); return *this; } mint inv() const { return pow(MOD - 2); } mint pow(u128 n) const { mint res(1), mul(*this); while (n > 0) { if (n & 1) res *= mul; mul *= mul; n >>= 1; } return res; } // other operators bool operator == (const mint &r) const { return (val >= MOD ? val - MOD : val) == (r.val >= MOD ? r.val - MOD : r.val); } bool operator != (const mint &r) const { return (val >= MOD ? val - MOD : val) != (r.val >= MOD ? r.val - MOD : r.val); } friend istream& operator >> (istream &is, mint &x) { long long t; is >> t; x = mint(t); return is; } friend ostream& operator << (ostream &os, const mint &x) { return os << x.get(); } friend mint modpow(const mint &r, long long n) { return r.pow(n); } friend mint modinv(const mint &r) { return r.inv(); } }; typename MontgomeryModInt64::u64 MontgomeryModInt64::MOD, MontgomeryModInt64::INV_MOD, MontgomeryModInt64::T128; template T pow_mod(T A, T N, T MOD){ T res = 1 % MOD; A %= MOD; while(N){ if(N & 1) res = (res * A) % MOD; A = (A * A) % MOD; N >>= 1; } return res; } bool MillerRabin(long long N, vector A){ using mint = MontgomeryModInt64; mint::set_mod(N); long long s = 0, d = N - 1; while(d % 2 == 0){ s++; d >>= 1; } for(auto a : A){ if(N <= a) return true; mint x = mint(a).pow(d); if(x != 1){ long long t; for(t = 0; t < s; t++){ if(x == N - 1) break; x *= x; } if(t == s) return false; } } return true; }; bool is_prime(long long N){ if(N <= 1) return false; if(N == 2) return true; if(N % 2 == 0) return false; if(N < 4759123141LL) return MillerRabin(N, {2, 7, 61}); else return MillerRabin(N, {2, 325, 9375, 28178, 450775, 9780504, 1795265022}); }; vector prime_factor(long long N){ assert(N >= 1); using u128 = __uint128_t; vector res; vector calc; while(N % 2 == 0){ N /= 2; res.push_back(2); } if(N == 1) return res; calc.push_back(N); while(calc.size()){ long long N = calc.back(); calc.pop_back(); long long x, y, c, g; auto f = [&](long long x){return (u128(x) * x + c) % N;}; while(!is_prime(N)){ x = rand() % N; y = x; c = (rand() % (N - 1)) + 1; g = 1; while(g == 1){ x = f(x); y = f(f(y)); g = gcd(abs(x - y), N); } if(g == N) continue; if(is_prime(N / g)) res.push_back(N / g); else calc.push_back(N / g); N = g; } res.push_back(N); } return res; }; template T pow_real(T A, T N, T INF){ T res = 1; while(N){ if(N & 1){ res = (res * A); if(res > INF) res = INF; } A = (A * A); if(A > INF) A = INF; N >>= 1; } return res; } int main(){ int n, m, l; cin >> n >> m >> l; int b = -1; { // ok >= b, ng < b int ok = 1000000001, ng = 0; while(ok - ng > 1){ int mid = (ok + ng) / 2; cout << "? " << mid << ' ' << 1 << "\n"; flush(cout); int res; cin >> res; if(res < mid) ok = mid; else ng = mid; } b = ok; } if(b == 1){ cout << "! 0\n"; return 0; } auto phi = [&](int x){ auto primes = prime_factor(x); sort(primes.begin(), primes.end()); primes.erase(unique(primes.begin(), primes.end()), primes.end()); for(int p : primes){ x /= p; x *= p - 1; } return x; }; auto phib = phi(b); // auto phiphib = phi(phib); n %= b; if(n == 0){ if(m == 0 and l > 0) cout << "! 1\n"; else cout << "! 0\n"; return 0; } int e_real = pow_real(m, l, 1001001001); int e = pow_mod(m, l, phib); int ans; if(e_real >= phib) ans = pow_mod(n, e + phib, b); else ans = pow_mod(n, e, b); cout << "! " << ans << "\n"; return 0; }