#pragma region header
#include <iostream>
#include <iomanip>
#include <cmath>
#include <vector>
#include <stdio.h>
#include <string.h>
#include <string>
#include <map>
#include <queue>
#include <set>
#include <stack>
using namespace std;
typedef long long ll;
template <class T> ll size(const T& x) { return x.size(); }
#define rep(i,a,b) for(ll i = (a); i < (b); i++)
#define iter(it,c) for(auto it = (c).begin(); it != (c).end();++it)
#define pb push_back
#define fs first
#define sc second
#define MOD 1000000007;
typedef pair<ll, ll> ii;
typedef vector<ll> vi;
typedef vector<ii> vii;
template <class T> T smod(T a, T b) {
	return (a % b + b) % b;
}

const int INF = ~(1 << 31);
const double pi = acos(-1);
const double EPS = 1e-9;

#pragma endregion

struct PrefixSum2D {
public:
	PrefixSum2D(vector<vi> A, int t_h, int t_w)
	{
		arr = A;
		h = t_h + 1; w = t_w + 1;
		row = vector<vi >(h, vi(w));
		col = vector<vi >(h, vi(w));
		pre = vector<vi >(h, vi(w));
		vis = vector<vector<bool> >(h, vector<bool>(w));
		get_prefix();
	}
	PrefixSum2D() { };

	int qsum(int y1, int x1, int y2, int x2) {
		y1++; x1++; y2++; x2++;
		//cout << y1 << ' ' << x1 << ' ' << y2 << ' ' << x2 << endl;
		return pre[y2][x2] - pre[y1 - 1][x2] - pre[y2][x1 - 1] + pre[y1 - 1][x1 - 1];
	}

private:
	vector<vi > arr;
	vector<vi > row;
	vector<vi > col;
	vector<vi > pre;
	vector<vector<bool> > vis;
	int h, w;
	void fill_pre(int i, int j) {
		if (i == 0 || j == 0 || vis[i][j]) return;
		vis[i][j] = true;
		pre[i - 1][j] = pre[i][j] - row[i - 1][j - 1];
		pre[i][j - 1] = pre[i][j] - col[i - 1][j - 1];
		fill_pre(i - 1, j);
		fill_pre(i, j - 1);
	}

	void get_prefix() // HxW matrix, cnt = sum of arr
	{
		ll cnt = 0;
		rep(i, 0, h - 1)rep(j, 0, w - 1) {
			vis[i][j] = 0;
			pre[i][j] = 0;
			cnt += arr[i][j];
		}
		rep(i, 0, h - 1) {
			rep(x, 0, w - 1) {
				if (i == 0) {
					col[i][x] = arr[i][x];
				}
				else
				{
					col[i][x] = arr[i][x] + col[i - 1][x];
				}

				if (x == 0) {
					row[i][x] = arr[i][x];
				}
				else {
					row[i][x] = arr[i][x] + row[i][x - 1];
				}
			}
		}
		rep(i, 0, h - 1) {
			pre[i][0] = 0;
		}
		rep(i, 0, w - 1) {
			pre[0][i] = 0;
		}
		pre[1][1] = arr[0][0];
		pre[h - 1][w - 1] = cnt;
		fill_pre(h - 1, w - 1);
	}
};

ll h, w, k;
PrefixSum2D P;
ll mem[1010];
vector<bool> Y;
ll mn = INF;

bool sqrsplit(int x1, int x2)
{
	vector<int> Ys;
	rep(i, 0, h - 1)
	{
		if (Y[i] == 1) Ys.pb(i);
	}

	bool f = true;
	ll sm = INF;
	if(Ys.size() > 0) sm = P.qsum(0, x1, Ys[0], x2);
	if (sm > k) f = false;
	if(Ys.size() > 1) rep(i, 1, Ys.size() - 1)
	{
		if (P.qsum(Ys[i - 1], x1, Ys[i], x2) > k)
		{
			f = false;
		}
	}
	if (Ys.size() > 0) { if (P.qsum(Ys[Ys.size() - 1], x1, h, x2) > k) f = false;  }
	else if (P.qsum(0, x1, h-1, x2) > 0) f = false;
	return f;
}

ll dp(int at, int lastx) {
	if (at == w)
	{
		if (sqrsplit(lastx, w))
		{
			return 0;
		}
		else {
			return -INF;
		}
	}
	ll mn = INF;
	if (sqrsplit(lastx, at)) mn = min(mn, 1 + dp(at + 1, at));
	mn = min(mn, dp(at + 1, lastx));
	return mn;
}

void bt(int at)
{
	if (at == h-1)
	{
		memset(mem, -1, sizeof(mem));
		mn = min(mn, dp(1, 0));
	}
	rep(i, 0, 2)
	{
		Y[at] = i;
		bt(at + 1);
	}
}

int main()
{
	/*cin >> h >> w >> k;
	Y = vector<bool>(h-1);
	vector< vi > A = vector<vi>(h, vi(w));
	rep(i, 0, h)
	{
		string in;
		cin >> in;
		rep(j, 0, in.size())
		{
			A[i][j] = in[j] - '0';
		}
	}
	P = PrefixSum2D(A, h, w);
	bt(0);
	cout << mn << endl;*/
	ll n, m;
	cin >> n >> m;
	cout << n * (n - 1) / 2 + m * (m - 1) / 2 << endl;
}


Measured memory_bytes: 256