Problem:
Score : 400 points

Problem Statement

There are N pieces of sushi. Each piece has two parameters: "kind of topping" t_i and "deliciousness" d_i.
You are choosing K among these N pieces to eat.
Your "satisfaction" here will be calculated as follows:

The satisfaction is the sum of the "base total deliciousness" and the "variety bonus".

The base total deliciousness is the sum of the deliciousness of the pieces you eat.

The variety bonus is x*x, where x is the number of different kinds of toppings of the pieces you eat.

You want to have as much satisfaction as possible.
Find this maximum satisfaction.

Constraints

1 \leq K \leq N \leq 10^5

1 \leq t_i \leq N

1 \leq d_i \leq 10^9

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N K
t_1 d_1
t_2 d_2
.
.
.
t_N d_N

Output

Print the maximum satisfaction that you can obtain.

Sample Input 1

5 3
1 9
1 7
2 6
2 5
3 1

Sample Output 1

26

If you eat Sushi 1,2 and 3:

The base total deliciousness is 9+7+6=22.

The variety bonus is 2*2=4.

Thus, your satisfaction will be 26, which is optimal.

Sample Input 2

7 4
1 1
2 1
3 1
4 6
4 5
4 5
4 5

Sample Output 2

25

It is optimal to eat Sushi 1,2,3 and 4.

Sample Input 3

6 5
5 1000000000
2 990000000
3 980000000
6 970000000
6 960000000
4 950000000

Sample Output 3

4900000016

Note that the output may not fit into a 32-bit integer type.

Solution in C# (Mono 4.6.2.0) (judge verdict: Runtime Error)

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



namespace CSharpSample01
{

    struct Sushi
    {
        public int t;
        public int d;
        public Sushi(int neta, int oisisa)
        {
            t = neta;
            d = oisisa;
        }
    }

    //Sushiノードの優先度付きキュー
    //おいしさdが対象
    class PriorityQueue_Sushi
    {
        int H;        
        Sushi[] heap;
        const int MAX = 2000000;

        public PriorityQueue_Sushi()
        {
            H = 0;
            heap = new Sushi[MAX];
        }

        public PriorityQueue_Sushi(int size)
        {
            H = size;
            heap = new Sushi[H + 1];
        }
       
        public void MaxHeapfy(int p)
        {
            while (2 * p <= H)
            {
                int son_n = 2 * p;
                Sushi son = heap[2 * p];
                if (2 * p + 1 <= H && son.d < heap[2 * p + 1].d)
                {
                    son = heap[2 * p + 1];
                    son_n++;
                }

                if (son.d > heap[p].d)
                {
                    Sushi tmp = heap[p];
                    heap[p] = son;
                    heap[son_n] = tmp;
                }
                else
                {
                    break;
                }

                p = son_n;
            }
        }

        public void BuildMaxHeap()
        {
            for (int s = H / 2; s >= 1; s--)
            {
                MaxHeapfy(s);
            }
        }

        public void Insert(Sushi key)
        {          
            H++;
            heap[H] = key;

            int son = H;

            while (son != 1)
            {
                int p = son / 2;
                if (heap[son].d > heap[p].d)
                {
                    Sushi tmp = heap[p];
                    heap[p] = heap[son];
                    heap[son] = tmp;
                    son /= 2;
                }
                else
                {
                    break;
                }
            }

        }

        public Sushi ExtractMax()
        {
            Sushi max = heap[1];
            heap[1] = heap[H];
            H--;

            MaxHeapfy(1);

            return max;
        }

        public int Count()
        {
            return H;
        }

    }

    class Program
    {
        static int N;
        static int K;
        static PriorityQueue_Sushi stomach;
        static PriorityQueue_Sushi not_eat;
        //t_cnt[i] := ネタiを何個食べたか
        static int[] t_cnt;
        //t_max[i] := ネタiのすしのおいしさdの最大値
        static int[] t_max;
        //入力されたすしを格納するsushi_list
        static List<Sushi> sushi_list;
        //ソートしたsushi_listの中のおいしさ上位K個のeat_sushi_list
        static List<Sushi> eat_sushi_list;

        static long max_point;
        static long d_sum;
        static long now_type_cnt;

        static void Create_stomach()
        {
            //最初に食べるK個のすしに対して
            //stamach生成(d_sumとnow_type_cntの更新)
            for (int i = 0; i < K; i++)
            {
                Sushi sushi = eat_sushi_list[i];
                d_sum += sushi.d;
                if (t_cnt[sushi.t] >= 1)
                {
                    stomach.Insert(sushi);
                }
                if (t_cnt[sushi.t] == 0)
                {
                    now_type_cnt++;
                }
                t_cnt[sushi.t]++;
            }
        }

        static void Create_not_eat()
        {
            //not_eat生成
            for (int i = K; i < N; i++)
            {
                Sushi sushi = sushi_list[i];
                if (t_cnt[sushi.t] == 0)
                {
                    t_max[sushi.t] = Math.Max(t_max[sushi.t], sushi.d);
                }
            }

            for (int i = 0; i < N; i++)
            {
                if (t_max[i] > 0) not_eat.Insert(new Sushi(i, t_max[i]));
            }
        }

        static void Updata_max_point()
        {
            //max_pointを更新
            while (true)
            {
                if (now_type_cnt == K || stomach.Count() == 0) break;

                Sushi sushi = stomach.ExtractMax();
                d_sum -= sushi.d;

                sushi = not_eat.ExtractMax();
                d_sum += sushi.d;

                ++now_type_cnt;

                max_point = Math.Max(max_point, d_sum + now_type_cnt * now_type_cnt);

            }
        }
        
        static void Main(string[] args)
        {
            //N, Kの入力
            string[] input = Console.ReadLine().Split(' ');
            N = int.Parse(input[0]);
            K = int.Parse(input[1]);

            t_cnt = new int[N + 1];
            t_max = new int[N + 1];
            sushi_list = new List<Sushi>();
            eat_sushi_list = new List<Sushi>();
            stomach = new PriorityQueue_Sushi();
            not_eat = new PriorityQueue_Sushi();

            //すし(ネタ, おいしさ)を入力
            for(int i = 0; i < N; i++)
            {
                input = Console.ReadLine().Split(' ');
                int t = int.Parse(input[0]);
                int d = int.Parse(input[1]);
                sushi_list.Add(new Sushi(t, d));
            }

            //sushi_listをdでソート
            sushi_list = sushi_list.OrderByDescending(x => x.d).ToList();

            for (int i = 0; i < K; i++) eat_sushi_list.Add(sushi_list[i]);
            eat_sushi_list = eat_sushi_list.OrderBy(x => x.t).ThenByDescending(x => x.d).ToList();

            
            max_point = 0;
            d_sum = 0;
            now_type_cnt = 0;

            //stomach生成
            Create_stomach();

            //max_pointの初期化
            max_point = d_sum + now_type_cnt * now_type_cnt;
            
            //not_eat生成
            Create_not_eat();

            Updata_max_point();

            Console.WriteLine(max_point);
        }
    }
}