//  [rust]
#[allow(dead_code)]
mod utils {
    use std::io::{self, BufRead, BufReader, Stdin, StdinLock};
    use std::mem;
    use std::ops::{Deref, DerefMut};
    use std::str::{self, FromStr};

    pub struct Scanner<R: BufRead> {
        reader: R,
        buf: Vec<u8>,
    }

    impl<R: BufRead> Scanner<R> {
        pub fn new(reader: R) -> Scanner<R> {
            Scanner {
                reader: reader,
                buf: Vec::new(),
            }
        }

        pub fn read<T: FromStr>(&mut self) -> T {
            self.read_until(|&b| b == b' ' || b == b'\n');
            self.parse()
        }

        pub fn reads(&mut self) -> &str {
            self.read_until(|&b| b == b' ' || b == b'\n');
            unsafe { str::from_utf8_unchecked(&self.buf) }
        }

        pub fn readl(&mut self) -> &str {
            self.read_until(|&b| b == b'\n');
            unsafe { str::from_utf8_unchecked(&self.buf) }
        }

        pub fn read_vec<T: FromStr>(&mut self, count: usize) -> Vec<T> {
            let mut vec = Vec::with_capacity(count);

            for _ in 0..count {
                vec.push(self.read());
            }

            return vec;
        }

        fn read_until<P: FnMut(&u8) -> bool>(&mut self, mut predicate: P) {
            self.buf.clear();
            let mut first = true;

            // https://doc.rust-lang.org/src/std/io/mod.rs.html#1623-1649
            loop {
                let (done, used) = {
                    let available = self.reader.fill_buf().unwrap();
                    if first && available.len() == 0 {
                        panic!("EOF reached.");
                    }

                    match available.iter().position(&mut predicate) {
                        Some(0) if first => {
                            (false, 1)
                        }
                        Some(i) => {
                            self.buf.extend_from_slice(&available[..i]);
                            (true, i + 1)
                        }
                        None => {
                            self.buf.extend_from_slice(available);
                            (false, available.len())
                        }
                    }
                };

                self.reader.consume(used);
                if done || used == 0 {
                    return;
                }

                first = false;
            }
        }

        #[inline]
        fn parse<T: FromStr>(&mut self) -> T {
            // 文字列をT型へパースする
            let elem = unsafe { str::from_utf8_unchecked(&self.buf) };
            elem.parse()
                .unwrap_or_else(|_| panic!(format!("failed parsing: {}", elem)))
        }
    }

    pub struct StdinScanner {
        stdin: Stdin,
        scanner: Scanner<BufReader<StdinLock<'static>>>,
    }

    impl StdinScanner {
        pub fn new() -> StdinScanner {
            let stdin = io::stdin();
            let stdinlock = unsafe { mem::transmute(stdin.lock()) };
            let reader = BufReader::new(stdinlock);
            let scanner = Scanner::new(reader);
            StdinScanner {
                stdin: stdin,
                scanner: scanner,
            }
        }
    }

    impl Deref for StdinScanner {
        type Target = Scanner<BufReader<StdinLock<'static>>>;

        #[inline]
        fn deref(&self) -> &Self::Target {
            &self.scanner
        }
    }

    impl DerefMut for StdinScanner {
        #[inline]
        fn deref_mut(&mut self) -> &mut Self::Target {
            &mut self.scanner
        }
    }
}

fn main() {
    let mut scanner = utils::StdinScanner::new();
    let n: usize = scanner.read();
    let m: usize = scanner.read();

    println!("{}", n * n.saturating_sub(1) / 2 + m * m.saturating_sub(1) / 2);
}