Problem: As you know, every birthday party has a cake! This time, Babaei is going to prepare the very special birthday party's cake.

Simple cake is a cylinder of some radius and height. The volume of the simple cake is equal to the volume of corresponding cylinder. Babaei has n simple cakes and he is going to make a special cake placing some cylinders on each other.

However, there are some additional culinary restrictions. The cakes are numbered in such a way that the cake number i can be placed only on the table or on some cake number j where j < i. Moreover, in order to impress friends Babaei will put the cake i on top of the cake j only if the volume of the cake i is strictly greater than the volume of the cake j.

Babaei wants to prepare a birthday cake that has a maximum possible total volume. Help him find this value.

Input

The first line of the input contains a single integer n (1 ≤ n ≤ 100 000) — the number of simple cakes Babaei has.

Each of the following n lines contains two integers ri and hi (1 ≤ ri, hi ≤ 10 000), giving the radius and height of the i-th cake.

Output

Print the maximum volume of the cake that Babaei can make. Your answer will be considered correct if its absolute or relative error does not exceed 10 - 6.

Namely: let's assume that your answer is a, and the answer of the jury is b. The checker program will consider your answer correct, if <image>.

Examples

Input

2
100 30
40 10


Output

942477.796077000


Input

4
1 1
9 7
1 4
10 7


Output

3983.539484752

Note

In first sample, the optimal way is to choose the cake number 1.

In second sample, the way to get the maximum volume is to use cakes with indices 1, 2 and 4.

Solution (in CPP):

Solution:
#include <bits/stdc++.h>
#pragma comment(linker, "/STACK:66777216")
#pragma warning(disable : 4996)
#pragma hdrstop
const long double PI = 3.14159265358979323846;
template <class T>
inline bool umax(T& a, const T& b) {
  return (a < b ? a = b, true : false);
}
namespace std {}
template <class T>
inline T sqr(const T& x) {
  return x * x;
}
namespace Random {}
inline bool is_digit(const char ch) { return (ch >= '0' && ch <= '9'); }
class IO {
 public:
  constexpr static const std::size_t kBufferSize = 1 << 18;
  IO()
      : read_bytes_count_(0),
        read_buffer_offset_(0),
        current_char_(0),
        eof_(false) {
    static_assert(kBufferSize > 32,
                  "Size of a buffer must be greater than 32 due to comparison "
                  "in IO::flush() method.");
  }
  ~IO() { flush(); }
  IO(const IO&) = delete;
  IO& operator=(const IO&) = delete;
  IO(const IO&&) = delete;
  IO& operator=(const IO&&) = delete;
  inline void shift_char();
  inline int32_t next_int();
  inline int64_t next_long();
  IO& operator>>(int32_t& x);
  IO& operator>>(int64_t& x);
  inline void flush();

 private:
  using Buffer = std::array<char, kBufferSize>;
  Buffer read_buffer_;
  Buffer write_buffer_;
  std::size_t read_bytes_count_;
  std::size_t read_buffer_offset_;
  std::size_t write_buffer_offset_;
  bool eof_;
  char current_char_;
  inline void update_buffer();
  template <typename T>
  T read_number();
};
extern bool useFastIO;
extern std::istream* pin;
extern std::ostream* pout;
extern IO io;
inline int32_t next_int();
inline int64_t next_long();
template <class T>
class SegmentTreeCmp {
 public:
  T* data;
  T* delayed;
  int offset, size, N;
  SegmentTreeCmp(const int N,
                 const std::function<bool(const T&, const T&)>& less,
                 const T& neutral)
      : N(N), less(less), neutral(neutral) {
    if (N & (N - 1)) {
      offset = 1 << (32 - __builtin_clz(N));
    } else {
      offset = 1 << (31 - __builtin_clz(N));
    }
    size = offset << 1;
    data = new T[size];
    delayed = new T[size];
    init();
  }
  ~SegmentTreeCmp() {
    delete[] data;
    delete[] delayed;
  }
  void init() {
    std::fill_n(data, size, neutral);
    std::fill_n(delayed, size, neutral);
  }
  T query(int l, int r) {
    l += offset;
    r += offset;
    T res = neutral;
    while (l <= r) {
      if (l & 1) {
        const T& cur = data[l++];
        if (less(cur, res)) {
          res = cur;
        }
      }
      if (!(r & 1)) {
        const T& cur = data[r--];
        if (less(cur, res)) {
          res = cur;
        }
      }
      l >>= 1;
      r >>= 1;
    }
    return res;
  }
  void update(int pos, const T& val) {
    pos += offset;
    data[pos] = val;
    pos >>= 1;
    while (pos >= 1) {
      const T &x = data[pos << 1], &y = data[(pos << 1) ^ 1];
      data[pos] = (less(x, y) ? x : y);
      pos >>= 1;
    }
  }

 private:
  std::function<bool(const T&, const T&)> less;
  T neutral;
};
using namespace std;
IO io;
const int MAXN = 111111;
int p[MAXN];
int64_t wh[MAXN];
void solve(istream& ins, ostream& out) {
  int n;
  io >> n;
  vector<pair<int64_t, int>> a(n);
  for (int i = 0; i < n; ++i) {
    int64_t r, h;
    io >> r >> h;
    int64_t v = sqr(r) * h;
    a[i] = {v, i};
  }
  sort(a.begin(), a.end());
  int cur_ind = 0;
  int cnt = 0;
  while (cur_ind < n) {
    int y = cur_ind;
    while (y < n && a[cur_ind].first == a[y].first) {
      ++y;
    }
    wh[cnt] = a[cur_ind].first;
    for (; cur_ind < y; ++cur_ind) {
      p[a[cur_ind].second] = cnt;
    }
    ++cnt;
  }
  SegmentTreeCmp<int64_t> tree(cnt, greater<int64_t>(), 0);
  tree.init();
  int64_t ans = 0;
  for (int i = 0; i < n; ++i) {
    int pr = p[i] - 1;
    int64_t cur_max;
    if (pr >= 0) {
      cur_max = tree.query(0, pr);
    } else {
      cur_max = 0;
    }
    int64_t new_max = cur_max + wh[p[i]];
    tree.update(p[i], new_max);
    umax(ans, new_max);
  }
  out << fixed << setprecision(16) << ans * PI << endl;
}
extern class IO io;
bool useFastIO = false;
istream* pin;
ostream* pout;
int main() {
  srand(time(NULL));
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  istream& in = cin;
  useFastIO = true;
  ostream& out = cout;
  out << fixed << setprecision(16);
  pin = &in;
  pout = &out;
  solve(in, out);
  return 0;
}
template <typename T>
T IO::read_number() {
  bool is_negative = false;
  while (!eof_ && !is_digit(current_char_) &&
         (std::is_unsigned<T>() || current_char_ != '-')) {
    shift_char();
  }
  if (std::is_signed<T>() && current_char_ == '-') {
    is_negative = true;
    shift_char();
  }
  T result = 0;
  while (!eof_ && is_digit(current_char_)) {
    result = (result << 3) + (result << 1) + current_char_ - '0';
    shift_char();
  }
  return (is_negative ? result * -1 : result);
}
inline void IO::update_buffer() {
  if (read_buffer_offset_ == read_bytes_count_) {
    read_bytes_count_ = fread(&read_buffer_[0], sizeof(read_buffer_[0]),
                              read_buffer_.size(), stdin);
    if (read_bytes_count_ == 0) {
      eof_ = true;
      return;
    }
    read_buffer_offset_ = 0;
  }
}
inline void IO::shift_char() {
  update_buffer();
  current_char_ = read_buffer_[read_buffer_offset_++];
}
inline int32_t IO::next_int() { return read_number<int32_t>(); }
inline int64_t IO::next_long() { return read_number<int64_t>(); }
IO& IO::operator>>(int32_t& x) {
  x = ::next_int();
  return *this;
}
IO& IO::operator>>(int64_t& x) {
  x = ::next_long();
  return *this;
}
inline void IO::flush() {
  fwrite(&write_buffer_[0], sizeof(write_buffer_[0]), write_buffer_offset_,
         stdout);
  write_buffer_offset_ = 0;
}
inline int32_t next_int() {
  if (useFastIO) {
    return io.next_int();
  }
  int32_t ret;
  *pin >> ret;
  return ret;
}
inline int64_t next_long() {
  if (useFastIO) {
    return io.next_long();
  }
  int64_t ret;
  *pin >> ret;
  return ret;
}