#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); sum += mod(mod(a[i] * m, prod) * p, prod); } return mod(sum,prod); } map frogcnt; //count amount 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; int64_t ans = MAX; //Given multiple buckets of elements, return all combinations of buckets. void combinator2(map > &frogties, vector &a, vector &x, int64_t superd, int64_t pos){ if( pos == frogties.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; } int cnt = 0; pivi t; for(pivi p : frogties) { if(cnt == pos) t = p; cnt++; } x.push_back(t.first); for( int64_t k : t.second){ a.push_back(k); combinator2(frogties,a,x,superd,pos + 1); a.pop_back(); } x.pop_back(); } void combinator3(vector > > &frogties, vector &a, vector &x, int64_t superd, int64_t pos){ if( pos == frogties.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}]; if(ans_pos < maxpos) { // prone to errors, so make WA variants ans_pos += superd * (1 + (maxpos - ans_pos - 1) / superd); } } ans = min(ans,ans_pos); return; } // int cnt = 0; // pivi t = frogties[pos]; // for(pivi p : frogties) { // if(cnt == pos) t = p; // cnt++; // } x.push_back(frogties[pos].first); for( int64_t k : frogties[pos].second){ // if(frogmax[{frogties[pos].first,k}] >= ans) continue; a.push_back(k); combinator3(frogties,a,x,superd,pos + 1); a.pop_back(); } x.pop_back(); } 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 amount 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}]; if(ans_pos < maxpos) { // prone to errors, so make WA variants ans_pos += superd * (1 + (maxpos - ans_pos - 1) / 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 int64_t superd = 1, ans_height = 0; for(int64_t p : jump_distances) { superd *= p; ans_height += frogbest[p].second; } vector a,x; vector > > frogties2; for(pivi p : frogties){ frogties2.push_back({p.first,p.second}); } // combinator2(frogties,a, x, superd, 0); combinator3(frogties2,a, x, superd, 0); cout << ans << " " << ans_height << endl; return 0; }