#include <bits/stdc++.h>
const int MAXN = 100005;
using namespace std;
struct Record {
  int num;
  long long v;
} cake[MAXN];
bool cmp(const Record& a, const Record& b) {
  if (a.v != b.v)
    return a.v < b.v;
  else
    return a.num > b.num;
}
struct Node {
  long long value;
  int left, right;
} tree[MAXN << 2];
void build_tree(int n) {
  int k = 1;
  while (k < n) k <<= 1;
  for (int i = 0; i < k; i++) {
    tree[k + i].left = tree[k + i].right = i + 1;
    tree[i].value = 0;
  }
  for (int i = k - 1; i > 0; i--) {
    tree[i].left = tree[(i << 1)].left;
    tree[i].right = tree[(i << 1 | 1)].right;
    tree[i].value = 0;
  }
}
void update(int k, long long value, int x) {
  if (tree[x].left == tree[x].right) {
    tree[x].value = value;
    return;
  }
  if (k <= tree[(x << 1)].right)
    update(k, value, (x << 1));
  else
    update(k, value, (x << 1 | 1));
  tree[x].value = max(tree[(x << 1)].value, tree[(x << 1 | 1)].value);
}
long long query(int l, int r, int x) {
  if (r == 0) return 0;
  if (tree[x].left == l && tree[x].right == r) return tree[x].value;
  if (r <= tree[(x << 1)].right)
    return query(l, r, (x << 1));
  else if (l >= tree[(x << 1 | 1)].left)
    return query(l, r, (x << 1 | 1));
  else
    return max(query(l, tree[(x << 1)].right, (x << 1)),
               query(tree[(x << 1 | 1)].left, r, (x << 1 | 1)));
}
int main() {
  int n;
  scanf("%d", &n);
  for (int i = 1; i <= n; i++) {
    long long r, h;
    scanf("%lld%lld", &r, &h);
    cake[i].num = i;
    cake[i].v = r * r * h;
  }
  sort(cake + 1, cake + n + 1, cmp);
  build_tree(n);
  for (int i = 1; i <= n; i++)
    update(cake[i].num, cake[i].v + query(1, cake[i].num - 1, 1), 1);
  printf("%.09Lf",
         (long double)query(1, n, 1) * 3.1415926535897932384626433832795);
  return 0;
}
