Okabe needs bananas for one of his experiments for some strange reason. So he decides to go to the forest and cut banana trees.

Consider the point (x, y) in the 2D plane such that x and y are integers and 0 ≤ x, y. There is a tree in such a point, and it has x + y bananas. There are no trees nor bananas in other points. Now, Okabe draws a line with equation <image>. Okabe can select a single rectangle with axis aligned sides with all points on or under the line and cut all the trees in all points that are inside or on the border of this rectangle and take their bananas. Okabe's rectangle can be degenerate; that is, it can be a line segment or even a point.

Help Okabe and find the maximum number of bananas he can get if he chooses the rectangle wisely.

Okabe is sure that the answer does not exceed 1018. You can trust him.

Input

The first line of input contains two space-separated integers m and b (1 ≤ m ≤ 1000, 1 ≤ b ≤ 10000).

Output

Print the maximum number of bananas Okabe can get from the trees he cuts.

Examples

Input

1 5


Output

30


Input

2 3


Output

25

Note

<image>

The graph above corresponds to sample test 1. The optimal rectangle is shown in red and has 30 bananas.
import java.io.*;
import java.util.*;

public class Main {

	class IOManager {
		BufferedReader reader;
		PrintWriter writer;
		StringTokenizer tokenizer;

		IOManager() {
			reader = new BufferedReader(new InputStreamReader(System.in));
			writer = new PrintWriter(new BufferedOutputStream(System.out));
		}

		IOManager(String file) throws FileNotFoundException {
			reader = new BufferedReader(new FileReader(file));
			writer = new PrintWriter(new BufferedOutputStream(System.out));
		}

		String next() throws IOException {
			while (tokenizer == null || !tokenizer.hasMoreTokens()) {
				String line = reader.readLine();
				if (line == null)
					throw new IOException("No lines left.");
				tokenizer = new StringTokenizer(line);
			}
			return tokenizer.nextToken();
		}

		public Integer nextInt() throws IOException {
			return Integer.parseInt(next());
		}

		public Long nextLong() throws IOException {
			return Long.parseLong(next());
		}

		public Double nextDouble() throws IOException {
			return Double.parseDouble(next());
		}

		public void writeSpace(Object obj) {
			writer.print(obj.toString() + " ");
		}

		public void writeLine(Object obj) {
			writer.println(obj.toString());
		}

		public void writeDouble(Double x, int n) {
			String format = "%." + n + "f";
			writer.printf(format, x);
		}

		public void write(Object obj) {
			writer.print(obj.toString());
		}

		public void close() {
			writer.close();
		}
	}

	class Pair implements Comparable {
		public long u, v;

		public Pair(long u, long v) {
			this.u = u;
			this.v = v;
		}

		@Override
		public int compareTo(Object o) {
			Pair that = (Pair) o;
			if (Long.compare(u, that.u) != 0)
				return Long.compare(u, that.u);
			return Long.compare(v, that.v);
		}
	}

	class Graph {
		public int n, m;
		public List<Integer>[] adj;

		public Graph(int n, int m) {
			this.n = n;
			this.m = m;
			adj = new List[n + 1];
			for (int i = 0; i <= n; ++i) {
				adj[i] = new ArrayList<>();
			}
		}

		public void add(int u, int v) {
			adj[u].add(v);
		}

		public void add2Ways(int u, int v) {
			add(u, v);
			add(v, u);
		}

		public void dfs(int i, boolean fr[]) {
			fr[i] = false;
			for (int j: adj[i]) {
				if (fr[j]) {
					dfs(j, fr);
				}
			}
		}

		public boolean isConnected() {
			boolean fr[] = new boolean[n + 1];
			Arrays.fill(fr, true);
			dfs(1, fr);
			for (int i = 2; i <= n; ++i) {
				if (fr[i])
					return false;
			}
			return true;
		}

		public boolean hasEuclideanPath() {
			if (!isConnected())
				return false;
			int cnt = 0;
			for (int i = 1; i <= n; ++i) {
				if (adj[i].size() % 2 == 1)
					cnt++;
			}
			return cnt <= 2;
		}

		public boolean dfsHamiltonian(int i, boolean[] fr, int reached) {
			fr[i] = false;
			reached++;
			if (reached == n)
				return true;
			for (int j: adj[i]) {
				if (fr[j]) {
					if (dfsHamiltonian(j, fr, reached))
						return true;
				}
			}
			fr[i] = true;
			return false;
		}

		public boolean hasHamiltonianPathFrom(int st) {
			boolean fr[] = new boolean[n + 1];
			Arrays.fill(fr, true);
			return dfsHamiltonian(st, fr, 0);
		}
	}

	// Actually rooted forest
	class Tree extends Graph {

		public Tree(int n, int m) {
			super(n, m);
		}

		public int getHeight(int i) {
			int res = 0;
			for (Integer j: adj[i]) {
				res = Math.max(res, getHeight(j) + 1);
			}
			return res;
		}
	}

	class FenwickTree {
		int n;
		int tree[];

		public FenwickTree() {

		}

		public FenwickTree(int maxn) {
			n = maxn;
			tree = new int[maxn + 10];
		}

		public void add(int i, int x) {
			while (i <= n) {
				tree[i] += x;
				i += i & (-i);
			}
		}

		public void add(int i) {
			add(i, 1);
		}

		public int get(int i) {
			int res = 0;
			while (i > 0) {
				res += tree[i];
				i -= i & (-i);
			}
			return res;
		}
	}

	IOManager ioManager;

	Main() {
		ioManager = new IOManager();
	}

	Main(String file) throws FileNotFoundException {
		ioManager = new IOManager(file);
	}

	long m, b;

	void solve() throws IOException {
		m = ioManager.nextLong();
		b = ioManager.nextLong();
		long res = 0;
		for (long x = 0; x <= m * b; x += m) {
			long y = -x / m + b;
			long sum = (x * (x + 1) / 2) * (y + 1) + (y * (y + 1) / 2) * (x + 1);
			res = Math.max(res, sum);
		}
		ioManager.writeLine(res);
	}

	void close() {
		ioManager.close();
	}

	public static void main(String args[]) throws IOException {
		Main solver;
//		solver = new Main();
        if (!"true".equals(System.getProperty("ONLINE_JUDGE"))) {
            solver = new Main("input.txt");
        } else {
            solver = new Main();
        }
		solver.solve();
		solver.close();
	}
}