Problem:
Score : 200 points

Problem Statement

We have a board with H horizontal rows and W vertical columns of squares.
There is a bishop at the top-left square on this board.
How many squares can this bishop reach by zero or more movements?

Here the bishop can only move diagonally.
More formally, the bishop can move from the square at the r_1-th row (from the top) and the c_1-th column (from the left) to the square at the r_2-th row and the c_2-th column if and only if exactly one of the following holds:

r_1 + c_1 = r_2 + c_2

r_1 - c_1 = r_2 - c_2

For example, in the following figure, the bishop can move to any of the red squares in one move:

Constraints

1 \leq H, W \leq 10^9

All values in input are integers.

Input

Input is given from Standard Input in the following format:

H \ W

Output

Print the number of squares the bishop can reach.

Sample Input 1

4 5

Sample Output 1

10

The bishop can reach the cyan squares in the following figure:

Sample Input 2

7 3

Sample Output 2

11

The bishop can reach the cyan squares in the following figure:

Sample Input 3

1000000000 1000000000

Sample Output 3

500000000000000000

Solution in C++14 (GCC 5.4.1) (judge verdict: Wrong Answer)

#include <bits/stdc++.h>
//上記が使用不可な環境において
/*
#include <iostream> // cout, endl, cin
#include <string> // string, to_string, stoi
#include <iomanip>  //setprecsion
#include <vector> // vector
#include <algorithm> // min, max, swap, sort, reverse, lower_bound, upper_bound
#include <utility> // pair, make_pair
#include <cmath>  //sin, cos, tan
#include <tuple> // tuple, make_tuple
#include <cstdint> // int64_t, int*_t
#include <cstdio> // printf
#include <map> // map
#include <queue> // queue, priority_queue
#include <set> // set
#include <stack> // stack
#include <deque> // deque
#include <unordered_map> // unordered_map
#include <unordered_set> // unordered_set
#include <bitset> // bitset
#include <cctype> // isupper, islower, isdigit, toupper, tolower
#include <cstdlib>
#include <cstring>
#include <numeric>
#include <complex>
#include <bitset>
#include <utility>
#include <functional>
*/
using namespace std;

typedef long long int ll;
typedef long long int lli;
typedef unsigned long long int ull;
typedef long double ld;
typedef string str;
typedef vector<char> vc;
typedef vector<bool> vb;
typedef vector<ld> vd;
typedef vector<str> vs;
typedef vector<ll> vll;
typedef vector<pair<ll, ll>> vpll;
typedef vector<vector<ll>> vvll;
typedef vector<vector<char>> vvc;
typedef vector<vector<str>> vvs;
const ld PI = acos(-1.0);
const ll MAX = 9000000000000000000;
const ll MIN = -9000000000000000000;
const ld DMAX = 4500;
const ld DMIN = -4500;

//謎
const int INF = INT_MAX;
const ll LLINF = 1LL << 60;
const ll MOD = 1000000007;
const ld EPS = 1e-9;
ll dx[8] = {1, 0, -1, 0, 1, -1, -1, 1};
ll dy[8] = {0, 1, 0, -1, 1, 1, -1, -1};

//0~nの範囲操作
#define rep(i, n) for (ll i = 0; i < (n); ++i)
//1~nの範囲操作
#define rrep(i, n) for (ll i = 1; i <= (n); ++i)
#define irep(it, stl) for (auto it = stl.begin(); it != stl.end(); it++)
#define drep(i, n) for (ll i = (n)-1; i >= 0; --i)
//出力後改行を
#define fin(ans) cout << (ans) << endl;
//出力後空白を
#define blank(ans) cout << (ans) << " ";
#define mp(p, q) make_pair(p, q)
#define pb(n) push_back(n)
//配列全操作
#define all(a) a.begin(), a.end()

//配列の合計
template <typename T>
T Sum(vector<T> n, ll a = 0, ll b = 0)
{
  if (b == 0)
  {
    return (accumulate(n.begin() + a, n.end(), 0));
  }
  else
  {
    return (accumulate(n.begin() + a, n.begin() + b, 0));
  }
}
template <>
ld Sum(vector<ld> n, ll a, ll b)
{
  if (b == 0)
  {
    return (accumulate(n.begin() + a, n.end(), 0));
  }
  else
  {
    return (accumulate(n.begin() + a, n.begin() + b, 0));
  }
}
//配列を昇順
template <typename T>
void Sort(T &n, ll a = 0, ll b = 0)
{
  if (b == 0)
  {
    return (sort(n.begin() + a, n.end()));
  }
  else
  {
    return (sort(n.begin() + a, n.begin() + b));
  }
}
//配列を降順
template <typename T>
void Reve(T &n, ll a = 0, ll b = 0)
{
  if (b == 0)
  {
    return (reverse(n.begin() + a, n.end()));
  }
  else
  {
    return (reverse(n.begin() + a, n.begin() + b));
  }
}
//配列nをmにコピー
template <typename T, typename U>
void Copy(T &n, U &m, ll a = 0, ll b = 0)
{
  copy(all(n), m.begin());
}
//小数点型に
template <typename T>
ld Cast(T n)
{
  return static_cast<ld>(n);
}
//配列入力
template <typename T>
void V(T &n)
{
  for (ll i = 0; i < n.size(); i++)
  {
    cin >> n[i];
  }
}
//２列配列入力
template <typename T, typename U>
void V2(T &n, U &m)
{
  for (ll i = 0; i < n.size(); i++)
  {
    cin >> n[i] >> m[i];
  }
}
//３列配列入力
template <typename T, typename U, typename W>
void V3(T &n, U &m, W &p)
{
  for (ll i = 0; i < n.size(); i++)
  {
    cin >> n[i] >> m[i] >> p[i];
  }
}
//yes, noと表示
void yn(bool a)
{
  if (a)
    cout << "yes" << endl;
  else
    cout << "no" << endl;
}
//Yes, Noと表示
void Yn(bool a)
{
  if (a)
    cout << "Yes" << endl;
  else
    cout << "No" << endl;
}
//YES, NOと表示
void YN(bool a)
{
  if (a)
    cout << "YES" << endl;
  else
    cout << "NO" << endl;
}
//yes, noと表示後終了
void fyn(bool a)
{
  if (a)
    cout << "yes" << endl;
  else
    cout << "no" << endl;
  exit(0);
}
//Yes, Noと表示後終了
void fYn(bool a)
{
  if (a)
    cout << "Yes" << endl;
  else
    cout << "No" << endl;
  exit(0);
}
//YES, NOと表示後終了
void fYN(bool a)
{
  if (a)
    cout << "YES" << endl;
  else
    cout << "NO" << endl;
  exit(0);
}
//AC, WAと表示
void AC(bool a)
{
  if (a)
    cout << "AC" << endl;
  else
    cout << "WA" << endl;
}
//AC, WAと表示後終了
void fAC(bool a)
{
  if (a)
    cout << "AC" << endl;
  else
    cout << "WA" << endl;
  exit(0);
}
//noneと表示後終了
void fnone(void)
{
  cout << "None" << endl;
  exit(0);
}
//Odd(奇数), Even(偶数)と表示後終了
void fOdd(bool a)
{
  if (a)
    cout << "Odd" << endl;
  else
    cout << "Even" << endl;
  exit(0);
}
//Possible, Impossibleと表示後終了
void Possible(bool a)
{
  if (a)
    cout << "Possible" << endl;
  else
    cout << "Impossible" << endl;
  exit(0);
}
//POSSIBLE, IMPOSSIBLEと表示後終了
void POSSIBLE(bool a)
{
  if (a)
    cout << "POSSIBLE" << endl;
  else
    cout << "IMPOSSIBLE" << endl;
  exit(0);
}
//四角　表示文字 a 縦幅 h 横幅 w
void square(char a, ll h, ll w)
{
  for (ll i = 0; i < h; i++)
  {
    for (ll j = 0; j < w; j++)
    {
      cout << a;
    }
    cout << endl;
  }
}
//四角枠　外周 a 中身 b 縦幅 h 横幅 w
void yoke(char a, char b, ll h, ll w)
{
  for (ll i = 0; i < h; i++)
  {
    for (ll j = 0; j < w; j++)
    {
      if (i == 0 || i == h - 1)
        cout << a;
      else if (j == 0 || j == w - 1)
        cout << a;
      else
        cout << b;
    }
    cout << endl;
  }
}
//四捨五入
ll C45(ll n)
{
  return (n + 1) / 2;
}
//文字列からcを探す
ll stcount(str s, char c)
{
  return count(s.cbegin(), s.cend(), c);
}
//素数
bool IsPrime(ll num)
{
  if (num < 2)
    return false;
  else if (num == 2)
    return true;
  else if (num % 2 == 0)
    return false;
  ld sqrtNum = sqrt(num);
  for (ll i = 3; i <= sqrtNum; i += 2)
  {
    if (num % i == 0)
      return false;
  }
  return true;
}
//桁数
ll GetDigit(ll num)
{
  return log10(num) + 1;
}
//各桁の和
ll KSum(ll n)
{
  ll sum = 0;
  if (n < 0)
    return 0;
  while (n > 0)
  {
    sum += n % 10;
    n /= 10;
  }
  return sum;
}
//数値反転
bool KReve(ll n)
{
  int reverse = 0;
  int remaind;
  int tmp = n;
  while (tmp != 0)
  {
    remaind = tmp % 10;
    reverse = reverse * 10 + remaind;
    tmp /= 10;
  }
  if (reverse == n)
    return true;
  else
    return false;
}
//約数全列挙
vector<ll> enum_div(ll n)
{
  vector<ll> ret;
  for (ll i = 1; i * i <= n; ++i)
  {
    if (n % i == 0)
    {
      ret.push_back(i);
      if (i != 1 && i * i != n)
      {
        ret.push_back(n / i);
      }
    }
  }
  return ret;
}
//最大公約数
ll gcd(ll a, ll b)
{
  return b ? gcd(b, a % b) : a;
}
//複数個の最大公約数
ll ngcd(vector<ll> a)
{
  ll res;
  res = a[0];
  for (ll i = 1; i < a.size() && res != 1; i++)
  {
    res = gcd(a[i], res);
  }
  return res;
}
//最小公倍数
ll lcm(ll a, ll b)
{
  return a * b / gcd(a, b);
}
//複数個の最小公倍数
ll nlcm(vector<ll> numbers)
{
  ll res;
  res = numbers[0];
  for (ll i = 1; i < numbers.size(); i++)
  {
    res = lcm(res, numbers[i]);
  }
  return res;
}
//累乗
ll Pow(ll x, ll n)
{
  ll res = 1;
  rep(i, n) res = res * x;
  return res;
}
//累乗(xのn乗%mod)
ll mod_pow(ll x, ll n, ll mod = MAX)
{
  ll res = 1;
  while (n > 0)
  {
    if (n & 1)
      res = res * x % mod;
    x = x * x % mod;
    n >>= 1;
  }
  return res;
}
//階乗
ll factorial(ll n)
{
  if (n > 0)
    return n * factorial(n - 1);
  else
    return 1;
}
//順列 nPr
ll perm(ll a, ll b)
{
  return (factorial(a) / factorial(a - b));
}
//組み合わせ　nCr
ll comb(ll a, ll b)
{
  return (factorial(a) / (factorial(a - b) * factorial(b)));
}
//n ~ mの和
ll sigma(ll n, ll m)
{
  return ((n + m) * (m - n + 1) * 0.5);
}
//期待値
ld hope(ld a)
{
  return (sigma(1, a) / a);
}
//謎
template <class T>
inline bool chmax(T &a, T b)
{
  if (a < b)
  {
    a = b;
    return 1;
  }
  return 0;
}
template <class T>
inline bool chmin(T &a, T b)
{
  if (a > b)
  {
    a = b;
    return 1;
  }
  return 0;
}
/*
//幅優先探索
// 各座標に格納したい情報を構造体にする
// 今回はX座標,Y座標,深さ(距離)を記述している
struct Corr
{
  ll x;
  ll y;
  ll depth;
};
queue<Corr> q;
ll bfs(vector<vector<ll>> grid)
{
  // 既に探索の場所を1，探索していなかったら0を格納する配列
  vector<vector<ll>> ispassed(grid.size(), vector<ll>(grid[0].size(), false));
  // このような記述をしておくと，この後のfor文が綺麗にかける
  ll dx[8] = {1, 0, -1, 0};
  ll dy[8] = {0, 1, 0, -1};
  while (!q.empty())
  {
    Corr now = q.front();
    q.pop();
    //今いる座標は(x,y)=(now.x, now.y)で，深さ(距離)はnow.depthである  ここで，今いる座標がゴール(探索対象)なのか判定する
    for (ll i = 0; i < 4; i++)
    {
      ll nextx = now.x + dx[i];
      ll nexty = now.y + dy[i];

      // 次に探索する場所のX座標がはみ出した時
      if (nextx >= grid[0].size())
        continue;
      if (nextx < 0)
        continue;

      // 次に探索する場所のY座標がはみ出した時
      if (nexty >= grid.size())
        continue;
      if (nexty < 0)
        continue;

      // 次に探索する場所が既に探索済みの場合
      if (ispassed[nexty][nextx])
        continue;

      ispassed[nexty][nextx] = true;
      Corr next = {nextx, nexty, now.depth + 1};
      q.push(next);
    }
  }
}
*/
//謎
//セグメント木
class Monoid
{
public:
  // 単位元
  ll unit;

  Monoid()
  {
    // 単位元
    unit = 0;
  }

  // 演算関数
  ll calc(ll a, ll b)
  {
    return a + b;
  }
};

class SegmentTree
{
public:
  // セグメント木の葉の要素数
  ll n;

  // セグメント木
  vector<ll> tree;

  // モノイド
  Monoid mono;

  SegmentTree(vector<ll> &v)
  {
    n = 1 << (ll)ceil(log2(v.size()));
    tree = vector<ll>(n << 1);
    for (ll i = 0; i < v.size(); i++)
    {
      update(i, v[i]);
    }
    for (ll i = v.size(); i < n; i++)
    {
      update(i, mono.unit);
    }
  }

  // k番目の値(0-indexed)をxに変更
  void update(ll k, ll x)
  {
    k += n;
    tree[k] = x;
    for (k = k >> 1; k > 0; k >>= 1)
    {
      tree[k] = mono.calc(tree[k << 1 | 0], tree[k << 1 | 1]);
    }
  }

  // [l, r)の最小値(0-indexed)を求める．
  ll query(ll l, ll r)
  {
    ll res = mono.unit;
    l += n;
    r += n;
    while (l < r)
    {
      if (l & 1)
      {
        res = mono.calc(res, tree[l++]);
      }
      if (r & 1)
      {
        res = mono.calc(res, tree[--r]);
      }
      l >>= 1;
      r >>= 1;
    }
    return res;
  }
  ll operator[](ll k)
  {
    // st[i]で添字iの要素の値を返す
    if (k - n >= 0 || k < 0)
    {
      return -INF;
    }
    return tree[tree.size() - n + k];
  }

  void show()
  {
    int ret = 2;
    for (ll i = 1; i < 2 * n; i++)
    {
      cout << tree[i] << " ";
      if (i == ret - 1)
      {
        cout << endl;
        ret <<= 1;
      }
    }
    cout << endl;
  }
};
//点と線の最短距離
struct Point
{
  ld x;
  ld y;
};

struct LineSegment
{
  Point start;
  Point end;
};

/**
   @brief 線分と点の距離を計算する。
   @param line 線分
   @param point 点
   @return ユークリッド距離
 */
ld calc_dist(const LineSegment &line, const Point &point)
{
  ld x0 = point.x, y0 = point.y;
  ld x1 = line.start.x, y1 = line.start.y;
  ld x2 = line.end.x, y2 = line.end.y;

  ld a = x2 - x1;
  ld b = y2 - y1;
  ld a2 = a * a;
  ld b2 = b * b;
  ld r2 = a2 + b2;
  ld tt = -(a * (x1 - x0) + b * (y1 - y0));

  if (tt < 0)
    return sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
  else if (tt > r2)
    return sqrt((x2 - x0) * (x2 - x0) + (y2 - y0) * (y2 - y0));

  ld f1 = a * (y1 - y0) - b * (x1 - x0);
  return sqrt((f1 * f1) / r2);
}
//文字を数字に
ll Moji(char a)
{
  return (a - 48);
}

//大文字->小文字(+32)

void Main()
{
  ll h, w; cin >> h >> w;
  if(h * w % 2 == 1) fin(h * w / 2 + 1)
  else fin(h * w / 2)
}

int main()
{
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout << fixed << setprecision(20);
  Main();
  return 0;
}
/*
//test時
g++ test.cpp -o a;./a
*/