Problem:
Score : 700 points

Problem Statement

Takahashi is playing with N cards.

The i-th card has an integer X_i on it.

Takahashi is trying to create as many pairs of cards as possible satisfying one of the following conditions:

The integers on the two cards are the same.

The sum of the integers on the two cards is a multiple of M.

Find the maximum number of pairs that can be created.

Note that a card cannot be used in more than one pair.

Constraints

2≦N≦10^5

1≦M≦10^5

1≦X_i≦10^5

Input

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

N M
X_1 X_2 ... X_N

Output

Print the maximum number of pairs that can be created.

Sample Input 1

7 5
3 1 4 1 5 9 2

Sample Output 1

3

Three pairs (3,2), (1,4) and (1,9) can be created.

It is possible to create pairs (3,2) and (1,1), but the number of pairs is not maximized with this.

Sample Input 2

15 10
1 5 6 10 11 11 11 20 21 25 25 26 99 99 99

Sample Output 2

6

Solution in C# (Mono 4.6.2.0) (judge verdict: Wrong Answer)

//#define TEST1
//#define TEST2

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

class Program
{
    static int N;
    static int M;
    static int[] X;

    static void Main()
    {
        //入力を受け取る
        int[] inputs = Console.ReadLine().Split().Select(int.Parse).ToArray();
        N = inputs[0];
        M = inputs[1];
        X = Console.ReadLine().Split().Select(int.Parse).ToArray();

        //Mで割ったあまりでグループ分け
        PriorityQueue<int>[] ss = new PriorityQueue<int>[M];
        ss = ss.Select(s => new PriorityQueue<int>()).ToArray();
        foreach (var x in X)
            ss[x % M].Enqueue(x);
#if TEST1
        Console.WriteLine("TEST1");
        foreach (var s in ss)
        {
            for (int i = 0; i < s.Count; i++)
                Console.Write("{0} ", s[i]);
            Console.WriteLine();
        }
#endif

        //答えの計算
        long ans = 0;
        ans += ss[0].Count / 2;
        if (M % 2 == 0)
            ans += ss[M / 2].Count / 2;
        for (int i = 1; i <= M / 2 - (M % 2 == 0 ? 1 : 0); i++)
        {
            int[] A = new int[ss[i].Count];
            int[] B = new int[ss[M - i].Count];
            for (int j = 0; j < ss[i].Count; j++)
                A[j] = ss[i][j];
            for (int j = 0; j < ss[M - i].Count; j++)
                B[j] = ss[M - i][j];
            if (B.Length > A.Length)
            {
                int[] temp = B;
                B = A;
                A = temp;
            }
#if TEST2
            Console.WriteLine("TEST2");
            foreach (var a in A)
                Console.Write("{0} ", a);
            Console.WriteLine();
            foreach (var b in B)
                Console.Write("{0} ", b);
            Console.WriteLine();
#endif
            ans += B.Length;
            int c = 0;
            int t = 1;
            for (int j = 1; j < A.Length; j++)
            {
                if (A[j] != A[j - 1])
                {
                    c += t / 2;
                    t = 1;
                }
                else
                    t++;
            }
            ans += Math.Min((A.Length - B.Length) / 2, c);
        }
#if TEST1 || TEST2
        Console.WriteLine("ANS");
#endif
        Console.WriteLine(ans);
    }
}

namespace PriorityQueue //優先度付きキュー
{
    using System;
    using System.Collections.Generic;
    class PriorityQueue<T>
    {
        private readonly List<T> heap;
        private readonly Comparison<T> compare;
        private int size;
        public PriorityQueue() : this(Comparer<T>.Default) { }
        public PriorityQueue(IComparer<T> comparer) : this(16, comparer.Compare) { }
        public PriorityQueue(Comparison<T> comparison) : this(16, comparison) { }
        public PriorityQueue(int capacity, Comparison<T> comparison)
        {
            this.heap = new List<T>(capacity);
            this.compare = comparison;
        }
        public void Enqueue(T item)
        {
            this.heap.Add(item);
            var i = size++;
            while (i > 0)
            {
                var p = (i - 1) >> 1;
                if (compare(this.heap[p], item) <= 0)
                    break;
                this.heap[i] = heap[p];
                i = p;
            }
            this.heap[i] = item;

        }
        public T Dequeue()
        {
            var ret = this.heap[0];
            var x = this.heap[--size];
            var i = 0;
            while ((i << 1) + 1 < size)
            {
                var a = (i << 1) + 1;
                var b = (i << 1) + 2;
                if (b < size && compare(heap[b], heap[a]) < 0) a = b;
                if (compare(heap[a], x) >= 0)
                    break;
                heap[i] = heap[a];
                i = a;
            }
            heap[i] = x;
            heap.RemoveAt(size);
            return ret;
        }
        private bool binary_search(T x, int imin, int imax)
        {
            if (imax < imin)
                return false;
            int imid = imin + (imax - imin) / 2;
            if (compare(heap[imid], x) > 0)
                return binary_search(x, imin, imid - 1);
            else if (compare(heap[imid], x) < 0)
                return binary_search(x, imid + 1, imax);
            return true;
        }
        public bool Contains(T x)
        {
            return binary_search(x, 0, heap.Count - 1);
        }
        public T Peek() { return heap[0]; }
        public int Count { get { return size; } }
        public bool Any() { return size > 0; }
        public T this[int index] { get { return heap[index]; } }
    }
}