Problem:
Score : 400 points

Problem Statement

Takahashi has N sticks that are distinguishable from each other. The length of the i-th stick is L_i.

He is going to form a triangle using three of these sticks. Let a, b, and c be the lengths of the three sticks used. Here, all of the following conditions must be satisfied:

a < b + c

b < c + a

c < a + b

How many different triangles can be formed? Two triangles are considered different when there is a stick used in only one of them.

Constraints

All values in input are integers.

3 \leq N \leq 2 \times 10^3

1 \leq L_i \leq 10^3

Input

Input is given from Standard Input in the following format:

N
L_1 L_2 ... L_N

Constraints

Print the number of different triangles that can be formed.

Sample Input 1

4
3 4 2 1

Sample Output 1

1

Only one triangle can be formed: the triangle formed by the first, second, and third sticks.

Sample Input 2

3
1 1000 1

Sample Output 2

0

No triangles can be formed.

Sample Input 3

7
218 786 704 233 645 728 389

Sample Output 3

23

Solution in C# (Mono 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Text;
using System.Linq;
using System.Collections;
using System.Collections.Generic;


class Program {

	static long mod = 1000000007;
	//static long mod =998244353;
	static int[] ans;
	static void Main(string[] args) {

		char[] cs = new char[] { ' ' };
		//char[] cs = new char[] { ' ', ',' };

		//int n = int.Parse(Console.ReadLine());
		//int val = int.Parse(Console.ReadLine());
		//int[] vals = parseAry(Console.ReadLine().Split(cs));
		//string str = Console.ReadLine();
		//string[] strs = Console.ReadLine().Split(cs);

		//string res = "";


		long res = 0;


		int n = int.Parse(Console.ReadLine());
		int[] vals = parseAry(Console.ReadLine().Split(cs));
		Array.Sort(vals);

		//List<int> zzz = new List<int>(vals);

		int[] bou = new int[2001];
		for ( int i = 0; i < n; i++ ) {
			bou[vals[i]]++;
		}
		List<int> lis = new List<int>();
		List<int> cnt = new List<int>();
		for ( int i = 0; i < 2000; i++ ) {
			if ( bou[i] > 0 ) { lis.Add(i); cnt.Add(bou[i]); }
		}

		int[] d = new int[n];
		d[0] = cnt[0];
		for ( int i = 1; i < cnt.Count; i++ ) {
			d[i] = d[i - 1] + cnt[i];
		}
 


		for ( int i = 0; i < vals.Length; i++ ) {
			for ( int k =i+1; k < vals.Length; k++ ) {

				int max = vals[i] + vals[k]-1;
				int min = Math.Max(vals[i] - vals[k], vals[k] - vals[i]);
				int po = Binary_SearchX(max,lis);


				if ( lis[po] > max ) { po--; }
				int right = po;
				right = Math.Max(right, 0);

				po = Binary_SearchX(min, lis);
				if ( lis[po] > min ) { po--; }
				int left = po;
				left = Math.Max(left, 0);


				if ( lis[left] <= vals[k] ) {
					int q = d[right] - (k+1);
					q = Math.Max(q, 0);
					res += q;
				} else { res += d[right] - d[left]; }

			}

		}




			Console.WriteLine(res);

		return;

	}

	static public int Binary_SearchX(int x, List<int> lis) {
		int Center = 0;
		int Lower = 0;
		int Upper = lis.Count - 1;
		while ( Lower <= Upper ) {
			Center = ( Lower + Upper ) >> 1;
			if ( x > lis[Center] ) {
				Lower = Center + 1;
			} else if ( x < lis[Center] ) {
				Upper = Center - 1;
			} else {
				return Center;
			}
		}
		return Center;
	}



	//	int配列をスペース区切りの文字列に変換
	static string stringBuilderArrayInt(int[] a) {
		StringBuilder sb = new StringBuilder();

		for ( int i = 0; i < a.Length; i++ ) {
			sb.Append(a[i] + " "); 
		}
		if ( sb.Length > 1 ) {
			sb = sb.Remove(sb.Length - 1, 1);
		}
		return sb.ToString(); ;
	}


	//	文字列strをindex番目からdで上書き
	static string strOverWrite(string str, int i, string s) {
		return str.Remove(i, s.Length).Insert(i, s);
	}

	//　String[]  ----->  int[]
	static int[] parseAry(string[] str) {
		int[] nums = new int[str.Length];
		for ( int i = 0; i < str.Length; i++ ) { nums[i] = int.Parse(str[i]); }
		return nums;
	}
	//　String[]  ----->  long[]
	static long[] parseAryL(string[] str) {
		long[] nums = new long[str.Length];
		for ( int i = 0; i < str.Length; i++ ) { nums[i] = long.Parse(str[i]); }
		return nums;
	}

	//文字列を1文字ずつString[]に入れる
	static string[] strAry(String str) {
		string[] re = new string[str.Length];
		for ( int i = 0; i < str.Length; i++ ) { re[i] = str[i].ToString(); }
		return re;
	}



}