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.Collections.Generic;
using System.ComponentModel.Design;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using static System.Console;

public static class Program
{
    private static readonly long INF = long.MaxValue / 2;
    private static readonly int MOD = 1000000007;

    struct Pair<T, U> : IComparable<Pair<T, U>>
        where T : IComparable<T>
        where U : IComparable<U>
    {
        public T first;
        public U second;
        private bool CompWithFirst;

        public Pair(T f, U s, int comp)
        {
            first = f;
            second = s;
            CompWithFirst = comp == 1;
        }

        public int CompareTo(Pair<T, U> other)
        {
            return CompWithFirst ? first.CompareTo(other.first) : second.CompareTo(other.second);
        }
    }

    public class PriorityQueue<T> where T : IComparable<T>
    {

        private List<T> Q;
        private readonly int r;

        public PriorityQueue(bool ascending)
        {
            if (ascending)
            {
                r = 1;
            }
            else
            {
                r = -1;
            }

            Q = new List<T>();
        }


        private void PushHeap(List<T> list, T item)
        {
            int n = list.Count();
            list.Add(item);

            while (n != 0)
            {
                int pIndex = (n - 1) / 2;

                if (list[n].CompareTo(list[pIndex]) * r > 0)
                {
                    Swap(Q, n, pIndex);
                }
                else
                {
                    break;
                }

                n = pIndex;
            }
        }

        private void PopHeap(List<T> list)
        {
            int n = list.Count() - 1;
            list[0] = list[n];
            list.RemoveAt(n);

            int cur = 0;
            int comp;

            while (2 * cur + 1 <= n - 1)
            {
                int c1 = 2 * cur + 1;
                int c2 = 2 * (cur + 1);
                if (c1 == n - 1)
                {
                    comp = c1;
                }
                else
                {

                    comp = list[c1].CompareTo(list[c2]) * r > 0 ? c1 : c2;
                }

                if (list[cur].CompareTo(list[comp]) * r < 0)
                {
                    Swap(Q, cur, comp);
                }
                else
                {
                    break;
                }

                cur = comp;
            }
        }

        private void Swap(List<T> list, int a, int b)
        {
            T keep = list[a];
            list[a] = list[b];
            list[b] = keep;
        }



        public void Enqueue(T value)
        {
            PushHeap(Q, value);
        }

        public T Dequeue()
        {
            T ret = Q[0];
            PopHeap(Q);
            return ret;
        }

        public T Peek()
        {
            return Q[0];
        }

        public int CountItem()
        {
            return Q.Count();
        }
    }

    static long ModInv(long a, long m)
    {
        long b = m, u = 1, v = 0;
        while (b != 0)
        {
            long t = a / b;
            a -= t * b;
            long tmp = a;
            a = b;
            b = tmp;
            u -= t * v;
            tmp = u;
            u = v;
            v = tmp;
        }

        u %= m;
        if (u < 0) u += m;
        return u;
    }

    public static long CalcComb(long n, long m)
    {
        //条件チェック
        if (n < m) return 0;
        if (n < 0 || m < 0) return 0;

        //nＣm ＝ nＣm-1 ×（n-m+1）/ m 
//         return CalcFact(n) / (CalcFact(m) * CalcFact(n - m));
        //MODで割ってbの逆元を求める
        return CalcFact(n) * ModInv((CalcFact(m) * CalcFact(n - m)) % MOD, MOD) % MOD;
    }

    /// <summary>
    /// 階乗を計算する。
    /// </summary>
    /// <param name="n">n</param>
    /// <returns>nの階乗（n!）</returns>
    public static long CalcFact(long n)
    {
        if (n <= 0)
        {
            return 1;
        }

        return n * CalcFact(n - 1) % MOD;
    }


    struct Pos
    {
        public int x;
        public int y;

        public Pos(int x, int y)
        {
            this.x = x;
            this.y = y;
        }
        
        public static Pos operator +(Pos p1, Pos p2)
        {
            var result = new Pos();
            result.x = p2.x + p1.x;
            result.y = p2.y + p1.y;
            return result;
        }

        public static Pos operator -(Pos p1, Pos p2)
        {
            var result = new Pos();
            result.x = p2.x - p1.x;
            result.y = p2.y - p1.y;
            return result;
        }
    }
    
    class Modular
    {
        private const int M = 1000000007;
        private long value;

        public Modular(long value)
        {
            this.value = value;
        }

        public static implicit operator Modular(long a)
        {
            var m = a % M;
            return new Modular((m < 0) ? m + M : m);
        }

        public static Modular operator +(Modular a, Modular b)
        {
            return a.value + b.value;
        }

        public static Modular operator -(Modular a, Modular b)
        {
            return a.value - b.value;
        }

        public static Modular operator *(Modular a, Modular b)
        {
            return a.value * b.value;
        }

        private static Modular Pow(Modular a, int n)
        {
            switch (n)
            {
                case 0:
                    return 1;
                case 1:
                    return a;
                default:
                    var p = Pow(a, n / 2);
                    return p * p * Pow(a, n % 2);
            }
        }

        public static Modular operator /(Modular a, Modular b)
        {
            return a * Pow(b, M - 2);
        }

        private static readonly List<int> facs = new List<int> {1};

        private static Modular Fac(int n)
        {
            for (int i = facs.Count; i <= n; ++i)
            {
                facs.Add((int) (Math.BigMul(facs.Last(), i) % M));
            }

            return facs[n];
        }

        public static Modular Ncr(int n, int r)
        {
            return (n < r) ? 0
                : (n == r) ? 1
                : Fac(n) / (Fac(r) * Fac(n - r));
        }

        public static explicit operator int(Modular a)
        {
            return (int) a.value;
        }
    }
    
    static class Permutation<T>
    {
        private static void Search(List<T[]> perms, Stack<T> stack, T[] a)
        {
            int N = a.Length;
            if (N == 0)
            {
                perms.Add(stack.Reverse().ToArray());
            }
            else
            {
                var b = new T[N - 1];
                Array.Copy(a, 1, b, 0, N - 1);
                for (int i = 0; i < a.Length; ++i)
                {
                    stack.Push(a[i]);
                    Search(perms, stack, b);
                    if (i < b.Length) { b[i] = a[i]; }
                    stack.Pop();
                }
            }
        }
        public static IEnumerable<T[]> All(IEnumerable<T> src)
        {
            var perms = new List<T[]>();
            Search(perms, new Stack<T>(), src.ToArray());
            return perms;
        }
    }
    
    static int nibunn(int[] array, int target)
    {
        int L = 0;
        int R = array.Length; 
            
        while(R - L > 1)
        {
            int mid = (R + L) / 2;
            if (array[mid] > target) L = mid;
            else R = mid;
        }
        return L;
    }

    public static void Main(string[] args)
    {
        int n = int.Parse(ReadLine());

        var list = ReadLine().Split(' ').Select(int.Parse).OrderBy(x => -x).ToArray();
        // 2 2 3 a <= b <= c
        // 2 < 2 + 3(自明)
        // 2 < 2 + 3
        // 3 < 2 + 2(自明)
        int ans = 0;
        //C#だとO(n^3)は間に合わない
        for (int i = 0; i < list.Length - 2; i++)
        {
            for (int j = i + 1; j < list.Length - 1; j++)
            {
                int a = list[i];
                int b = list[j];
                // 3~6  i=1, j=2
                // 3~7  
                int k = (n - j) / 2;
                int c = j + k;

                int target = list[i] - list[j];
                int[] tmp = new int[n - j];
                Array.Copy(list, j, tmp, 0, n - j);
                ans += nibunn(tmp,target);

                
//                if (b >= a + c) break;
//                WriteLine($"a:{a}, b:{b}, c:{c}");
//                ans++;
            }
        }
        WriteLine(ans);
    }
}