Problem:
Score : 100 points

Problem Statement

Kyoto University Programming Contest is a programming contest voluntarily held by some Kyoto University students.
This contest is abbreviated as Kyoto University Programming Contest and called KUPC.

source: Kyoto University Programming Contest Information

The problem-preparing committee met to hold this year's KUPC and N problems were proposed there.
The problems are numbered from 1 to N and the name of i-th problem is P_i.
However, since they proposed too many problems, they decided to divide them into some sets for several contests.

They decided to divide this year's KUPC into several KUPCs by dividing problems under the following conditions.

One KUPC provides K problems.

Each problem appears at most once among all the KUPCs.

All the first letters of the problem names in one KUPC must be different.

You, one of the committee members, want to hold as many KUPCs as possible.
Write a program to find the maximum number of KUPCs that can be held this year.

Constraints

1 \leq N \leq 10^4

1 \leq K \leq 26

1 \leq |P_i| \leq 10

All characters in P_i are capital letters.

Note that, for each i and j (1 \leq i < j \leq N),
P_i \neq P_j are not necessarily satisfied.

Input

The input is given from Standard Input in the following format:

N K
P_1
:
P_N

Output

Print the maximum number of KUPCs that can be held on one line.

Sample Input 1

9 3
APPLE
ANT
ATCODER
BLOCK
BULL
BOSS
CAT
DOG
EGG

For example, three KUPCs can be held by dividing the problems as follows.

First: APPLE, BLOCK, CAT

Second: ANT, BULL, DOG

Third: ATCODER, BOSS, EGG

Sample Output 1

3

Sample Input 2

3 2
KU
KYOUDAI
KYOTOUNIV

Sample Output 2

0

No KUPC can be held.

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

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


class Segtree<T>
{
    int n;
    T[] tree;
    Func<T, T, T> f;
    T exnum;
    public Segtree(int m, Func<T, T, T> f, T ex)
    {
        this.f = f;
        this.exnum = ex;
        n = 1;
        while (n < m) n <<= 1;

        tree = new T[(n << 1) - 1];
        for (int i = 0; i < tree.Length; i++) tree[i] = ex;
    }
    public Segtree(int m, T ini, Func<T, T, T> f, T ex)
    {
        this.f = f;
        this.exnum = ex;
        n = 1;
        while (n < m) n <<= 1;

        tree = new T[(n << 1) - 1];
        for (int i = 0; i < tree.Length; i++) tree[i] = ini;
        for (int i = 0; i < m; ++i) update(i, ini);
    }
    public void update(int j, T x)
    {
        int i = j + n - 1;
        tree[i] = x;
        while (i > 0)
        {
            i = (i - 1) >> 1;
            tree[i] = f(tree[(i << 1) + 1], tree[(i << 1) + 2]);
        }
    }
    public T look(int i) { return tree[i + n - 1]; }

    // [s, t]
    public T run(int s, int t) { return query(s, t + 1, 0, 0, n); }
    T query(int s, int t, int k, int l, int r)
    {
        if (r <= s || t <= l) return exnum;
        if (s <= l && r <= t) return tree[k];

        return f(query(s, t, (k << 1) + 1, l, (l + r) >> 1), query(s, t, (k + 1) << 1, (l + r) >> 1, r));
    }
}

class PriorityQueue<T>
{
    private Comparison<T> comp;
    private List<T> list;
    private int count;
    public PriorityQueue() : this((x, y) => ((IComparable<T>)x).CompareTo(y)) { }
    public PriorityQueue(Comparison<T> comparison)
    {
        comp = comparison;
        list = new List<T>();
        count = 0;
    }
    public void Enqueue(T x)
    {
        var pos = count++;
        list.Add(x);
        while (pos > 0)
        {
            var p = (pos - 1) / 2;
            if (comp(list[p], x) <= 0) break;
            list[pos] = list[p];
            pos = p;
        }
        list[pos] = x;
    }
    public T Dequeue()
    {
        var value = list[0];
        var x = list[--count];
        list.RemoveAt(count);
        if (count == 0) return value;
        var pos = 0;
        while (pos * 2 + 1 < count)
        {
            var a = 2 * pos + 1;
            var b = 2 * pos + 2;
            if (b < count && comp(list[b], list[a]) < 0) a = b;
            if (comp(list[a], x) >= 0) break;
            list[pos] = list[a];
            pos = a;
        }
        list[pos] = x;
        return value;
    }
    public T Peek() { return list[0]; }
    public bool Any() { return count > 0; }
    public int Count() { return count; }
}

namespace Codeforces
{
    class Program
    {
        const long InfL = 4011686018427387913L;
        static char[] sep = new char[] { ' ', '/' };

        /* static int get_int => int.Parse(Console.ReadLine());
        static int[] get_intArr => Console.ReadLine().Split(sep).Select(a => int.Parse(a)).ToArray();
        static List<int> get_intList => Console.ReadLine().Split(sep).Select(a => int.Parse(a)).ToList<int>();
        static string get_string => Console.ReadLine().Trim();
        static string[] get_strArr => Console.ReadLine().Split(sep);
        static List<string> get_strList => Console.ReadLine().Split(sep).ToList<string>();
        */

        static int[] dx = { -1, 0, 1, -1, 1, -1, 0, -1 };
        static int[] dy = { 1, 1, 1, 0, 0, -1, -1, -1 };


        /// <summary>
        /// basic dfs function
        /// </summary>
        /// 
        /* List<bool> visited;
        List<List<int>> adj;

        static void dfs(int here)
        {
            visited[here] = true;

            for(int i = 0; i<adj[here].Count; i++)
            {
                int there = adj[here][i];
                if (!visited[there])
                    dfs(there);
            }
        }

        static void dfsAll()
        {
            for(int i = 0; i<adj.Count; i++)
            {
                if (!visited[i]) dfs(i);
            }
        } */

        static void Main(string[] args)
        {
            int[] input_arr = Console.ReadLine().Split(sep).Select(f => int.Parse(f)).ToArray();
            int n = input_arr[0];
            int k = input_arr[1];
            int result = 0;
            bool complete = false;

            int[] char_arr = new int[26];
            for(int i = 0; i < n; i++)
            {
                string input = Console.ReadLine();
                char_arr[input[0] - 'A']++;
            }

            List<int> count = new List<int>();
            for (int i = 0; i < 26; i++) if(char_arr[i] != 0) count.Add(-1 * char_arr[i]);
            count.Sort();

            while (!complete)
            {
                int k_copy = k;
                int pos = 0;
                while(k_copy > 0)
                {
                    if(count.Count == 0)
                    {
                        complete = true;
                        break;
                    }
                    if(count[pos] != 0)
                    {
                        k_copy--;
                        count[pos]++;
                        if (count[pos] == 0)
                        {
                            count.RemoveAt(pos);
                        }
                        else pos++;
                        
                        if (k_copy == 0) { result++; break; }
                        if (pos == count.Count) break;
                        continue;
                    }
                    
                    if(pos == count.Count-1)
                    {
                        complete = true;
                        break;
                    }
                }
                count.Sort();
            }

            Console.WriteLine(result);

        }
        
        class mymath
        {
            static int Mod = 1000000007;
            public void setMod(int m) { Mod = m; }
            public bool isprime(long a)
            {
                if (a < 2) return false;
                for (long i = 2; i * i <= a; i++) if (a % i == 0) return false;
                return true;
            }
            public bool[] sieve(int n)
            {
                var isp = new bool[n + 1];
                for (int i = 2; i <= n; i++) isp[i] = true;
                for (int i = 2; i * i <= n; i++) if (isp[i]) for (int j = i * i; j <= n; j += i) isp[j] = false;
                return isp;
            }
            public List<int> getprimes(int n)
            {
                var prs = new List<int>();
                var isp = sieve(n);
                for (int i = 2; i <= n; i++) if (isp[i]) prs.Add(i);
                return prs;
            }
            public long[][] E(int n)
            {
                var ret = new long[n][];
                for (int i = 0; i < n; i++)
                {
                    ret[i] = new long[n];
                    ret[i][i] = 1;
                }
                return ret;
            }
            public long[][] powmat(long[][] A, long n)
            {
                if (n == 0) return E(A.Length);
                var t = powmat(A, n / 2);
                if ((n & 1) == 0) return mulmat(t, t);
                return mulmat(mulmat(t, t), A);
            }
            public long[] mulmat(long[][] A, long[] x)
            {
                int n = A.Length, m = x.Length;
                var ans = new long[n];
                for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) ans[i] = (ans[i] + x[j] * A[i][j]) % Mod;
                return ans;
            }
            public long[][] mulmat(long[][] A, long[][] B)
            {
                int n = A.Length, m = B[0].Length, l = B.Length;
                var ans = new long[n][];
                for (int i = 0; i < n; i++)
                {
                    ans[i] = new long[m];
                    for (int j = 0; j < m; j++) for (int k = 0; k < l; k++) ans[i][j] = (ans[i][j] + A[i][k] * B[k][j]) % Mod;
                }
                return ans;
            }
            public long[] addmat(long[] x, long[] y)
            {
                int n = x.Length;
                var ans = new long[n];
                for (int i = 0; i < n; i++) ans[i] = (x[i] + y[i]) % Mod;
                return ans;
            }
            public long[][] addmat(long[][] A, long[][] B)
            {
                int n = A.Length, m = A[0].Length;
                var ans = new long[n][];
                for (int i = 0; i < n; i++) ans[i] = addmat(A[i], B[i]);
                return ans;
            }
            public long powmod(long a, long b)
            {
                if (a >= Mod) return powmod(a % Mod, b);
                if (a == 0) return 0;
                if (b == 0) return 1;
                var t = powmod(a, b / 2);
                if ((b & 1) == 0) return t * t % Mod;
                return t * t % Mod * a % Mod;
            }
            public long inv(long a) { return powmod(a, Mod - 2); }
            public long gcd(long a, long b)
            {
                while (b > 0) { var t = a % b; a = b; b = t; }
                return a;
            }
            public long lcm(long a, long b) { return a * (b / gcd(a, b)); }
            public long Comb(int n, int r)
            {
                if (n < 0 || r < 0 || r > n) return 0;
                if (n - r < r) r = n - r;
                if (r == 0) return 1;
                if (r == 1) return n;
                var numerator = new int[r];
                var denominator = new int[r];
                for (int k = 0; k < r; k++)
                {
                    numerator[k] = n - r + k + 1;
                    denominator[k] = k + 1;
                }
                for (int p = 2; p <= r; p++)
                {
                    int pivot = denominator[p - 1];
                    if (pivot > 1)
                    {
                        int offset = (n - r) % p;
                        for (int k = p - 1; k < r; k += p)
                        {
                            numerator[k - offset] /= pivot;
                            denominator[k] /= pivot;
                        }
                    }
                }
                long result = 1;
                for (int k = 0; k < r; k++) if (numerator[k] > 1) result = result * numerator[k] % Mod;
                return result;
            }
        }
    }
}