#include <bits/stdc++.h>
using namespace std;
struct point {
int64_t x, y;
};
enum dir { RIGHT, LEFT, UP, DOWN };
enum linetype { NORMAL, X_PLUS_Y, X_MINUS_Y, X_EQUALS_CONST, Y_EQUALS_CONST };
int64_t get(linetype type, int64_t x, int64_t y) {
return array<int64_t, 5>({0, x + y, x - y, x, y})[type];
};
enum onwhat { ON_X, ON_Y };
struct maptype {
linetype linetyp;
onwhat onwha;
dir direction;
auto operator<=>(const maptype &) const = default;
};
struct fraction {
int64_t n, d;
void normalize() {
if (d < 0) {
n = -n, d = -d;
}
int64_t g = gcd(n >= 0 ? n : -n, d);
n /= g, d /= g;
}
fraction(int64_t n = 0) : n(n), d(1) {}
fraction(int64_t n, int64_t d) : n(n), d(d) { normalize(); }
auto operator<=>(const fraction &o) const { return n * o.d <=> o.n * d; }
fraction operator+(const fraction &o) const { return fraction(n * o.d + o.n * d, d * o.d); }
fraction operator-(const fraction &o) const { return fraction(n * o.d - o.n * d, d * o.d); }
fraction operator*(const fraction &o) const { return fraction(n * o.n, d * o.d); }
fraction operator/(const fraction &o) const { return fraction(n * o.d, d * o.n); }
template <typename T>
friend fraction operator+(T x, const fraction &f) { return fraction(x) + f; }
template <typename T>
friend fraction operator-(T x, const fraction &f) { return fraction(x) - f; }
template <typename T>
friend fraction operator*(T x, const fraction &f) { return fraction(x) * f; }
};
template <typename T>
using min_heap = priority_queue<T, vector<T>, greater<T>>;
static const array<array<dir, 3>, 4> choose = {{{{LEFT, DOWN, DOWN}}, {{LEFT, UP, UP}}, {{RIGHT, RIGHT, DOWN}}, {{RIGHT, RIGHT, UP}}}};
array<onwhat, 4> diron = {ON_Y, ON_Y, ON_X, ON_X};
array<linetype, 4> ltype = {Y_EQUALS_CONST, Y_EQUALS_CONST, X_EQUALS_CONST, X_EQUALS_CONST};
static const array<array<dir, 3>, 4> dirlock = {{{{RIGHT, RIGHT, RIGHT}}, {{LEFT, LEFT, LEFT}}, {{RIGHT, LEFT, RIGHT}}, {{LEFT, RIGHT, LEFT}}}};
static const array<array<dir, 3>, 4> dirwant = {{{{DOWN, UP, LEFT}}, {{UP, DOWN, RIGHT}}, {{LEFT, RIGHT, DOWN}}, {{RIGHT, LEFT, UP}}}};
static const array<array<int, 3>, 4> use_ub = {{{{0, 1, 0}}, {{1, 0, 1}}, {{0, 1, 0}}, {{1, 0, 1}}}};
int solve(int n, vector<point> a) {
vector<dir> dirs = {RIGHT};
for (int i = 1; i < n; ++i) {
auto [x, y] = a[i];
dirs.push_back(choose[(x < 0) * 2 + (y < 0)][(abs(y) < abs(x) ? 0 : abs(y) == abs(x) ? 1 : 2)]);
}
map<maptype, map<int, set<pair<fraction, int>>>> mps;
for (int i = 0; i < n; ++i) {
auto [x, y] = a[i];
mps[{X_MINUS_Y, ON_X, dirs[i]}][x - y].insert({x, i});
mps[{X_MINUS_Y, ON_Y, dirs[i]}][x - y].insert({y, i});
mps[{X_PLUS_Y, ON_X, dirs[i]}][x + y].insert({x, i});
mps[{X_PLUS_Y, ON_Y, dirs[i]}][x + y].insert({y, i});
mps[{X_EQUALS_CONST, ON_Y, dirs[i]}][x].insert({y, i});
mps[{Y_EQUALS_CONST, ON_X, dirs[i]}][y].insert({x, i});
}
min_heap<pair<fraction, pair<int64_t, pair<linetype, dir>>>> pq;
pq.push({0, {0, {NORMAL, LEFT}}});
vector vis(n, vector<int>(9));
auto flat = [](pair<linetype, dir> p) -> int { return p.first + 4 * (p.first != NORMAL && p.second != LEFT); };
while (!pq.empty()) {
auto [t, p] = pq.top();
auto [i, m] = p;
pq.pop();
if (vis[i][flat(m)]) {
continue;
}
vis[i][flat(m)] = 1;
auto [x, y] = a[i];
if (m.first != NORMAL) {
pq.push({t, {i, {NORMAL, LEFT}}});
int c = m.first == X_EQUALS_CONST;
auto *st = &mps[{m.first, c ? ON_Y : ON_X, dirs[i]}][get(m.first, x, y)];
int64_t qty = c ? y : x;
auto it = st->find({qty, i});
int s = m.first == X_EQUALS_CONST || m.first == Y_EQUALS_CONST;
if (m.second == RIGHT && it != --st->end()) {
pq.push({t + (next(it)->first - qty) / (s + 1), {next(it)->second, m}});
}
if (m.second == LEFT && it != st->begin()) {
pq.push({t + (qty - prev(it)->first) / (s + 1), {prev(it)->second, m}});
}
continue;
}
auto add = [&](fraction dist, int64_t y, linetype z, dir direc) { pq.push({dist, {y, {z, direc}}}); };
auto lb = [&](set<pair<fraction, int>> &st, int64_t val, int mul, linetype linetyp, dir direc) {
if (auto it = st.lower_bound({val + mul * t, -1}); it != st.end()) {
add((it->first - val) / mul, it->second, linetyp, direc);
}
};
auto ub = [&](set<pair<fraction, int>> &st, int64_t val, int mul, linetype linetyp, dir direc) {
if (auto it = st.upper_bound({val - mul * t, n}); it != st.begin()) {
it--;
add((val - it->first) / mul, it->second, linetyp, direc);
}
};
int64_t qty = int(dirs[i]) < 2 ? y : x;
array<function<void(set<pair<fraction, int>> &, int64_t, int, linetype, dir)>, 2> f = {lb, ub};
f[use_ub[dirs[i]][0]](mps[{X_MINUS_Y, diron[dirs[i]], dirwant[dirs[i]][0]}][x - y], qty, 1, X_MINUS_Y, dirlock[dirs[i]][0]);
f[use_ub[dirs[i]][1]](mps[{X_PLUS_Y, diron[dirs[i]], dirwant[dirs[i]][1]}][x + y], qty, 1, X_PLUS_Y, dirlock[dirs[i]][1]);
f[use_ub[dirs[i]][2]](mps[{ltype[dirs[i]], onwhat(1 - int(diron[dirs[i]])), dirwant[dirs[i]][0]}][get(ltype[dirs[i]], x, y)], x + y - qty, 2, ltype[dirs[i]], dirlock[dirs[i]][2]);
}
int ans = 0;
for (int i = 0; i < n; ++i) {
ans += vis[i][NORMAL];
}
return ans;
}
int32_t main() {
cin.tie(nullptr)->sync_with_stdio(false);
int n;
cin >> n;
vector<point> a(n);
for (auto &[x, y] : a) {
cin >> x >> y;
}
for (auto &[x, y] : a | views::drop(1)) {
x -= a[0].x, y -= a[0].y;
}
a[0] = {0, 0};
auto rotate = [&]() {
for (auto &[x, y] : a) {
int64_t nx = y, ny = -x;
x = nx, y = ny;
}
};
int ans = solve(n, a);
rotate();
ans = max(ans, solve(n, a));
rotate();
ans = max(ans, solve(n, a));
rotate();
cout << max(ans, solve(n, a)) << '\n';
}