#include <bits/stdc++.h>

using namespace std;

#define M_DEBUG if (0)

/******************************************************************************
	typedef
******************************************************************************/
typedef unsigned long long int ullint;
typedef long long int llint;

/*! 与えられた3つの非負整数 a, b, c を辺の長さとする三角形が存在するか */
bool isTriangle(ullint a, ullint b, ullint c)
{
	return ((a < b + c) && (b < a + c) && (c < a + b));
}

/*!
	nCk の全組み合わせに対して処理 f を行う関数 foreach_comb と、
	再帰的に組み合わせを探索する内部関数 recursive_comb
*/
void recursive_comb(ullint *indexes, llint s, ullint rest, function<void(ullint *)> f)
{
	M_DEBUG cout << "s: " << s << " rest: " << rest << endl;
	if (rest == 0)
	{
		f(indexes);
	}
	else
	{
		if (s < 0)
			return;
		recursive_comb(indexes, s - 1, rest, f);
		indexes[rest - 1] = s;
		recursive_comb(indexes, s - 1, rest - 1, f);
	}
}

// nCkの組み合わせに対して処理を実行する
void foreach_comb(ullint n, llint k, function<void(ullint *)> f)
{
	// int indexes[k];
	ullint *indexes = new ullint[k];
	recursive_comb(indexes, n - 1, k, f);
	delete indexes;
}

/******************************************************************************
	Main
******************************************************************************/
int main()
{
	ullint n = 0;
	cin >> n;
	assert(n >= 3 && n <= 2000);

	vector<ullint> l_list;
	for (ullint i = 0; i < n; i++)
	{
		ullint l_i = 0;
		cin >> l_i;
		assert(l_i >= 1 && l_i <= 1000);
		l_list.push_back(l_i);
	}

	ullint answer = 0;
	// これでは計算量がO(N^3)になるのでNG
	// foreach_comb(n, 3, [&answer, &l_list](ullint *indexes) {
	// 	M_DEBUG cout << "isTriangle(" << l_list[indexes[0]] << ',' << l_list[indexes[1]] << ',' << l_list[indexes[2]]  << ") = " << isTriangle(l_list[indexes[0]], l_list[indexes[1]], l_list[indexes[2]]) << endl;
	// 	if (isTriangle(l_list[indexes[0]], l_list[indexes[1]], l_list[indexes[2]])) {
	// 		answer++;
	// 	}
	// });

	sort(l_list.begin(), l_list.end()); //昇順
	M_DEBUG
	{
		for (auto a : l_list)
		{
			cout << a << " ";
		}
		cout << endl;
	}
	foreach_comb(n, 2, [n, &l_list, &answer](ullint *indexes) {
		auto itr = lower_bound(l_list.begin(), l_list.end(), l_list[indexes[0]] + l_list[indexes[1]]); // a + b > c で第3の辺の探索数を削る
		ullint ng = distance(itr, l_list.end());
		M_DEBUG cout << l_list[indexes[0]] << ',' << l_list[indexes[1]];
		
		//  b + c > a(1), a + c > b(2) をチェックする
		
		// ...が、次のような愚直なチェックは不要。
		// while (itr != l_list.begin()) {
		// 	if (*itr <= l_list[indexes[1]]) break;  // 既にチェックした組み合わせ
		// 	M_DEBUG cout << "isTriangle(" << l_list[indexes[0]] << ',' << l_list[indexes[1]] << ',' << *itr << ") = " << isTriangle(l_list[indexes[0]], l_list[indexes[1]], *itr) << endl;
		// 	if (isTriangle(l_list[indexes[0]], l_list[indexes[1]], *itr)) {
		// 		answer++;
		// 	}
		// 	itr--;
		// }
		
		// なぜなら a < b なので a < b + c が成り立つから(1)はチェックしなくてよい。
		// あとは c > b - a であれば条件(2)を満たす。なので、lower_bound( , , b - a) から c までの要素はすべて(2)を満たす。
		// しかし b より前の要素を数えてしまうと、既に a と b の組み合わせで調べているので二重カウントしてしまう。
		// よって b の次から数えればよく、その個数は N - (n - index of c) - (indexes[1] +1)
		answer += n - indexes[1] - 1 - ng;
		M_DEBUG
		{
			itr--;
			cout << ',' << *itr << endl;
		}
	});
	cout << answer << endl;

	return 0;
}


Measured memory_bytes: 512