#include <bits/stdc++.h>
using namespace std;
const long long MOD = 1000000007ll;
const long long INF = 2000000000ll;
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;
}
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};
long power(long a, long b) {
  return b ? power(a * a % MOD, b / 2) * (b % 2 ? a : 1) % MOD : 1;
}
long perm(int N, int K) {
  long x = 1;
  for (int i = 1; i <= K; i++) {
    x = x * (N - i + 1) % MOD;
  }
  return x % MOD;
}
long factorial(int N) { return perm(N, N); }
long comb(int N, int K) {
  long x = 1, y = 1;
  for (int i = 1; i <= K; i++) {
    x = x * (N - i + 1) % MOD;
    y = y * i % MOD;
  }
  return x * power(y, MOD - 2) % MOD;
}
long hcomb(int N, int K) { return comb(N + K - 1, N - 1); }
int dtoi(double d) {
  if ((double)2 * d - floor(d) - ceil(d) >= 0)
    return ceil(d);
  else
    return floor(d);
}
bool isprime(int n) {
  if (n < 2) return false;
  for (int i = 2; i * i <= n; ++i) {
    if (n % i == 0) return false;
  }
  return true;
}
void eratosthenes(int n) {
  bitset<1000000> is_prime(0);
  for (int i = 2; i <= n; ++i) is_prime.set(i);
  for (int i = 2; i <= n; ++i) {
    if (is_prime[i]) {
      for (int j = i * 2; j <= n; j += i) {
        is_prime.reset(j);
      }
    }
  }
  for (int i = 2; i <= n; ++i) {
    if (is_prime[i]) cout << i << "\n";
  }
}
void dfs(const vector<vector<int> > &G, int v, vector<int> &seen) {
  seen[v] = true;
  for (int next_v : G[v]) {
    if (seen[next_v]) continue;
    dfs(G, next_v, seen);
  }
}
void bfs(const vector<vector<int> > &G, int v, vector<int> &dist) {
  for (int i = 0; i < int((dist).size()); i++) dist[i] = -1;
  queue<int> que;
  dist[v] = 0;
  que.push(v);
  while (!que.empty()) {
    v = que.front();
    que.pop();
    for (int next_v : G[v]) {
      if (dist[next_v] != -1) continue;
      dist[next_v] = dist[v] + 1;
      que.push(next_v);
    }
  }
}
int knapsack01(int N, int W, vector<int> &value, vector<int> &weight) {
  vector<vector<int> > dp(N + 1, vector<int>(W + 1, 0));
  for (int i = 0; i < N; i++)
    for (int j = 0; j < W + 1; j++) {
      if (j - weight[i] >= 0)
        dp[i + 1][j] = max(dp[i][j - weight[i]] + value[i], dp[i][j]);
      else
        dp[i + 1][j] = dp[i][j];
    }
  return dp[N][W];
}
int knapsack01_reuse(int N, int W, vector<int> &value, vector<int> &weight) {
  vector<int> dp(W + 1, 0);
  dp[0] = 0;
  for (int i = 0; i < N; i++) {
    for (int j = W; j > 0; j--) {
      if (j - weight[i] >= 0) dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
    }
  }
  return dp[W];
}
int knapsack(int N, int W, vector<int> &value, vector<int> &weight) {
  vector<vector<int> > dp(N + 1, vector<int>(W + 1, 0));
  for (int i = 0; i < N; i++)
    for (int j = 0; j < W + 1; j++) {
      dp[i + 1][j] = max(dp[i][j], dp[i + 1][j]);
      if (j - weight[i] >= 0)
        dp[i + 1][j] = max(dp[i + 1][j - weight[i]] + value[i], dp[i + 1][j]);
    }
  return dp[N][W];
}
int knapsack_reuse(int N, int W, vector<int> &value, vector<int> &weight) {
  vector<int> dp(W + 1, 0);
  dp[0] = 0;
  for (int i = 0; i < N; ++i) {
    for (int w = weight[i]; w <= W; ++w) {
      dp[w] = max(dp[w], dp[w - weight[i]] + value[i]);
    }
  }
  return dp[W];
}
int longest_increasing_subsequence(int n, vector<int> &A) {
  vector<int> L(n + 1, 0);
  L[0] = A[0];
  int length = 1;
  for (int i = 1; i < n; i++) {
    if (L[length - 1] < A[i])
      L[length++] = A[i];
    else
      *lower_bound(L.begin(), next(L.begin(), length), A[i]) = A[i];
  }
  return length;
}
int longest_common_subsequence(string X, string Y) {
  int m = X.length();
  int n = Y.length();
  int res = 0;
  X = ' ' + X;
  Y = ' ' + Y;
  vector<vector<int> > c(m + 1, vector<int>(n + 1, 0));
  for (int i = 1; i < m + 1; i++)
    for (int j = 1; j < n + 1; j++) {
      if (X[i] == Y[j])
        c[i][j] = c[i - 1][j - 1] + 1;
      else
        c[i][j] = max(c[i - 1][j], c[i][j - 1]);
      res = max(res, c[i][j]);
    }
  return res;
}
void dijkstra(int n, const vector<vector<pair<int, int> > > &G, int v,
              vector<int> &dist) {
  priority_queue<pair<int, int> > pq;
  vector<int> color(n, 0);
  for (int i = 0; i < n; i++) dist[i] = INF;
  dist[v] = 0;
  pq.push(make_pair(0, v));
  color[v] = 1;
  while (!pq.empty()) {
    pair<int, int> f = pq.top();
    pq.pop();
    int u = f.second;
    color[u] = 2;
    if (dist[u] < f.first * (-1)) continue;
    for (int j = 0; j < G[u].size(); j++) {
      v = G[u][j].first;
      if (color[v] == 2) continue;
      if (dist[v] > dist[u] + G[u][j].second) {
        dist[v] = dist[u] + G[u][j].second;
        pq.push(make_pair(dist[v] * (-1), v));
        color[v] = 1;
      }
    }
  }
}
int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout << fixed << setprecision(10);
  long long H, W;
  cin >> H >> W;
  if (H == 1 || W == 1)
    cout << 1 << "\n";
  else {
    if (H % 2 == 0)
      cout << H * W / 2 << "\n";
    else {
      if (W % 2 == 0)
        cout << H * W / 2 << "\n";
      else
        cout << H * (W / 2) + (H + 1) / 2 << "\n";
    }
  }
}
