Problem:
Score : 300 points

Problem Statement

Takahashi has N balls. Initially, an integer A_i is written on the i-th ball.

He would like to rewrite the integer on some balls so that there are at most K different integers written on the N balls.

Find the minimum number of balls that Takahashi needs to rewrite the integers on them.

Constraints

1 \leq K \leq N \leq 200000

1 \leq A_i \leq N

All input values are integers.

Input

Input is given from Standard Input in the following format:

N K
A_1 A_2 ... A_N

Output

Print the minimum number of balls that Takahashi needs to rewrite the integers on them.

Sample Input 1

5 2
1 1 2 2 5

Sample Output 1

1

For example, if we rewrite the integer on the fifth ball to 2, there are two different integers written on the balls: 1 and 2.
On the other hand, it is not possible to rewrite the integers on zero balls so that there are at most two different integers written on the balls, so we should print 1.

Sample Input 2

4 4
1 1 2 2

Sample Output 2

0

Already in the beginning, there are two different integers written on the balls, so we do not need to rewrite anything.

Sample Input 3

10 3
5 1 3 2 4 1 1 2 3 4

Sample Output 3

3

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

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

namespace arc086_a
{
    class Program
    {
        static void Main(string[] args)
        {
            var NK = GetIntList();
            var N = NK[0];
            var K = NK[1];
            var al = GetIntList();
            var ad = new Dictionary<int, int>();

            var pq = new PriorityQueue<int>();


            for (int i = 0; i < N; i++)
            {
                if (!ad.ContainsKey(al[i])) ad.Add(al[i], 0);
                ad[al[i]]++;
            }

            foreach(var v in ad.Values) 
                pq.Push(-1 * v);

            int r = 0;
            int pqc = pq.Count;

            for (int i = 0; i < pqc - K; i++) 
            {
                r += -1 * pq.Top;
                pq.Pop();
            }

            Console.WriteLine(r);
        }

        public static string GetStr() => Console.ReadLine();
        public static int GetInt() => int.Parse(Console.ReadLine());
        public static long GetLong() => long.Parse(Console.ReadLine());
        public static double GetDouble() => double.Parse(Console.ReadLine());
        public static decimal GetDecimal() => decimal.Parse(Console.ReadLine());

        public static List<string> GetStrList() => Console.ReadLine().Split(' ').ToList();
        public static List<int> GetIntList() => Console.ReadLine().Split(' ').Select(x => int.Parse(x)).ToList();
        public static List<long> GetLongList() => Console.ReadLine().Split(' ').Select(x => long.Parse(x)).ToList();
        public static List<double> GetDoubleList() => Console.ReadLine().Split(' ').Select(x => double.Parse(x)).ToList();
        public static List<decimal> GetDecimalList() => Console.ReadLine().Split(' ').Select(x => decimal.Parse(x)).ToList();
        
        /// <summary>
        /// 優先度付き待ち行列
        /// </summary>
        /// <typeparam name="T">要素の型</typeparam>
        public class PriorityQueue<T>
          where T : IComparable<T>
        {
            #region フィールド

            public IList<T> buffer;

            #endregion
            #region 初期化

            public PriorityQueue() { this.buffer = new List<T>(); }
            public PriorityQueue(int capacity) { this.buffer = new List<T>(capacity); }

            #endregion
            #region ヒープ操作

            /// <summary>
            /// ヒープ化されている配列リストに新しい要素を追加する。
            /// </summary>
            /// <param name="array">対象の配列リスト</param>
            static void PushHeap(IList<T> array, T elem)
            {
                int n = array.Count;
                array.Add(elem);

                while (n != 0)
                {
                    int i = (n - 1) / 2;
                    if (array[n].CompareTo(array[i]) > 0)
                    {
                        T tmp = array[n]; array[n] = array[i]; array[i] = tmp;
                    }
                    n = i;
                }
            }

            /// <summary>
            /// ヒープから最大値を削除する。
            /// </summary>
            /// <param name="array">対象の配列リスト</param>
            static void PopHeap(IList<T> array)
            {
                int n = array.Count - 1;
                array[0] = array[n];
                array.RemoveAt(array.Count - 1);

                for (int i = 0, j; (j = 2 * i + 1) < n;)
                {
                    if ((j != n - 1) && (array[j].CompareTo(array[j + 1]) < 0))
                        j++;
                    if (array[i].CompareTo(array[j]) < 0)
                    {
                        T tmp = array[j]; array[j] = array[i]; array[i] = tmp;
                    }
                    i = j;
                }
            }

            #endregion
            #region 要素の挿入・削除

            /// <summary>
            /// 要素のプッシュ。
            /// </summary>
            /// <param name="elem">挿入したい要素</param>
            public void Push(T elem)
            {
                PushHeap(this.buffer, elem);
            }

            /// <summary>
            /// 要素を1つポップ。
            /// </summary>
            /// <remarks>
            /// 今回の実装では、先頭要素の読み出しと削除は別に行う。
            /// この Pop では削除のみ。
            /// 読み出しには Top プロパティを使う。
            /// </remarks>
            public void Pop()
            {
                PopHeap(this.buffer);
            }

            /// <summary>
            /// 先頭要素の読み出し。
            /// </summary>
            public T Top
            {
                get { return this.buffer[0]; }
            }

            public int Count
            {
                get { return this.buffer.Count; }
            }

            #endregion
        }

    }
}