#include #include #include #include #include #include #include using namespace std; using ll = long long; int64_t mod(int64_t a, int64_t b) { return ((a % b) + b) % b; } int64_t MAX = (1LL << 62) - 1 + (1LL << 62); typedef pair pii; typedef pair, vector> pvivi; typedef pair> pivi; // given relative prime a and b, calculate x s.t. a * x = 1 modulo b int64_t mul_inv(int64_t a, int64_t b) { int64_t x0 = 0, x1 = 1; if(b == 1) return 1; while(b) { int64_t q = a / b; int64_t t = b; b = a % b; a = t; t = x0; x0 = x1 - q * x0; x1 = t; } return x1; } int64_t mulmod(int64_t a, int64_t b, int64_t m) { if(abs(a) < abs(MAX / b)) { return a * b % m; } cout << a << " " << b << endl; cout << "dead" << endl; // Detects overflow -> WA solution. return __int128(a) * __int128(b) % m; } // Calculate the X that satisfies all a_i mod x_i and is smallest modulo product_i x_i int64_t my_crt(vector a, vector x, int64_t limit) { int64_t sum = 0, prod = 1; for(int64_t p : x) prod *= p; for(int64_t i = 0; i < a.size(); i++) { int64_t p = prod / x[i]; int64_t m = mul_inv(p, x[i]); sum += mulmod(mulmod(a[i], m, prod), p, prod); } return mod(sum, prod); } map frogcnt; // count number of frogs per modulo class map frogmax; // keep the largest position known per modulo class map frogbest; // Keep the largest modulo class per jump distance map> frogties; // Keep all tied modulo classes per jump distance set jump_distances; // Given multiple buckets of elements, return all combinations of buckets. pii combinator(map> &frogties) { // Calculate product of primes and height. int64_t superd = 1, ans_height = 0; for(int64_t p : jump_distances) { superd *= p; ans_height += frogbest[p].second; } // Calculate number of possibilities int64_t total = 1; for(pivi p : frogties) total *= p.second.size(); int64_t ans = MAX; for(int64_t i = 0; i < total; i++) { int64_t prod = 1; vector a, x; int64_t maxpos = 0; for(pivi p : frogties) { int64_t pos = (i / prod) % p.second.size(); a.push_back(p.second[pos]); x.push_back(p.first); maxpos = max(maxpos, frogmax[{p.first, p.second[pos]}]); prod *= p.second.size(); } int64_t X = my_crt(a, x, ans); int64_t ans_pos = X; for(int64_t j = 0; j < x.size(); j++) { int64_t p = x[j], c = a[j]; int64_t maxpos = frogmax[{p, c}]; int64_t k = ceil((double)(maxpos - X) / (double)superd); ans_pos = max(ans_pos, X + k * superd); } ans = min(ans, ans_pos); } return {ans, ans_height}; } int main() { ios::sync_with_stdio(false); cin.tie(0); int64_t n; cin >> n; for(int64_t i = 0; i < n; i++) { // Reading position x and jump distance d int64_t x, d; cin >> x >> d; jump_distances.insert(d); // Category jump distance d, pos x % d has one extra frog frogcnt[{d, x % d}]++; frogmax[{d, x % d}] = max(frogmax[{d, x % d}], x); // If this category is now the biggest, update best category for this jump distance. if(frogcnt[{d, x % d}] == frogbest[d].second) { // We found a tie, add it to the list frogties[d].push_back(x % d); } if(frogcnt[{d, x % d}] > frogbest[d].second) { // Save the best pair: (category offset, size of category) frogties[d] = vector(); frogties[d].push_back(x % d); frogbest[d] = {x % d, frogcnt[{d, x % d}]}; } } pii ans = combinator(frogties); // Find all possible CRT combinations cout << ans.first << " " << ans.second << endl; return 0; }