#define _CRT_SECURE_NO_WARNINGS #include using namespace std; int main() { int n; cin >> n; assert(2 <= n && n <= (int)2e5); vector a(n); vector b(n); for (int i = 0; i < n; i++) { cin >> a[i] >> b[i]; assert(1 <= a[i] && a[i] <= (int)2e5); assert(1 <= b[i] && b[i] <= (long long)1e9); } int a_max = *max_element(a.begin(), a.end()); long long res = 0; // 各 A[i] に対して最大の B[i] を対応付ける. vector a_to_bmax(a_max + 1, -1); for (int i = 0; i < n; i++) { if (a_to_bmax[a[i]] == -1) { a_to_bmax[a[i]] = b[i]; } else { // それと同時に A[i] = A[j] のタイプを先に処理する. res = max(res, min(a_to_bmax[a[i]], b[i])); a_to_bmax[a[i]] = max(a_to_bmax[a[i]], b[i]); } } // A[i] と A[j] の公約数 g を決め打つ. for (int g = 1; 2 * g <= a_max; g++) { // (A[i], B[i]) を積 A[i] B[i] について昇順ソートする. vector> ab_a_b; for (int a = g; a <= a_max; a += g) { long long b = a_to_bmax[a]; if (b == -1) continue; ab_a_b.emplace_back(a * b, a, b); } sort(ab_a_b.begin(), ab_a_b.end()); int K = (int)ab_a_b.size(); // A[i] の上からの累積最小値を求める. vector a_min(K + 1); a_min[K] = a_max + 1; for (int k = K - 1; k >= 0; k--) { auto [ab, a, b] = ab_a_b[k]; a_min[k] = min(a_min[k + 1], a); } // 各 A[i] を採用する場合の調和度の最大値を求める. for (int k = 0; k < K - 1; k++) { auto [ab, a, b] = ab_a_b[k]; res = max(res, (b * g) / a_min[k + 1]); } } cout << res << endl; }