Problem:
Score : 500 points

Problem Statement

AtCoDeer is thinking of painting an infinite two-dimensional grid in a checked pattern of side K.
Here, a checked pattern of side K is a pattern where each square is painted black or white so that each connected component of each color is a K × K square.
Below is an example of a checked pattern of side 3:

AtCoDeer has N desires.
The i-th desire is represented by x_i, y_i and c_i.
If c_i is B, it means that he wants to paint the square (x_i,y_i) black; if c_i is W, he wants to paint the square (x_i,y_i) white.
At most how many desires can he satisfy at the same time?

Constraints

1 ≤ N ≤ 10^5

1 ≤ K ≤ 1000

0 ≤ x_i ≤ 10^9

0 ≤ y_i ≤ 10^9

If i ≠ j, then (x_i,y_i) ≠ (x_j,y_j).

c_i is B or W.

N, K, x_i and y_i are integers.

Input

Input is given from Standard Input in the following format:

N K
x_1 y_1 c_1
x_2 y_2 c_2
:
x_N y_N c_N

Output

Print the maximum number of desires that can be satisfied at the same time.

Sample Input 1

4 3
0 1 W
1 2 W
5 3 B
5 4 B

Sample Output 1

4

He can satisfy all his desires by painting as shown in the example above.

Sample Input 2

2 1000
0 0 B
0 1 W

Sample Output 2

2

Sample Input 3

6 2
1 2 B
2 1 W
2 2 B
1 0 B
0 6 W
4 5 W

Sample Output 3

4

Solution in Java8 (OpenJDK 1.8.0) (judge verdict: Wrong Answer)

import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.TreeSet;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author Mirio
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        FReader in = new FReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        TaskD solver = new TaskD();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskD {
        public void solve(int testNumber, FReader in, PrintWriter out) {
            int n = in.nextInt();
            int k = in.nextInt();
            int k2 = k * 2;

            TreeSet<Pair<Integer, Integer>>[] c = new TreeSet[] {
                    new TreeSet<Pair<Integer, Integer>>(),
                    new TreeSet<Pair<Integer, Integer>>()
            };

            TaskD.BIT2D bitB = new TaskD.BIT2D(k2);
            TaskD.BIT2D bitW = new TaskD.BIT2D(k2);

            for(int i = 0; i < n; ++i) {
                int x = (in.nextInt() % k2);
                int y = (in.nextInt() % k2);

                if(in.next().charAt(0) == 'B')
                    bitB.update(x, y);
                else
                    bitW.update(x, y);
            }

            int ans = 0;
            for(int offsetX = 0; offsetX < k; ++offsetX) {
                for(int offsetY = 0; offsetY < k; ++offsetY) {
                    int pAns = 0, bx, by, wx, wy;

                    bx = 0 + offsetX;
                    by = 0 + offsetY;
                    pAns += bitB.get(bx, by, bx + k - 1, by + k - 1);

                    bx = k + offsetX;
                    by = k + offsetY;
                    pAns += bitB.get(bx, by, k2 - 1, k2 - 1);
                    if(offsetY != 0 && offsetX == 0) {
                        pAns += bitB.get(bx, 0, k2 - 1, offsetY - 1);
                    } else if(offsetY == 0 && offsetX != 0) {
                        pAns += bitB.get(0, by, offsetX - 1, k2 - 1);
                    } else if(offsetY != 0 && offsetX != 0) {
                        pAns += bitB.get(bx, 0, k2 - 1, offsetY - 1);
                        pAns += bitB.get(0, by, offsetX - 1, k2 - 1);
                        pAns += bitB.get(0, 0, offsetX - 1, offsetY - 1);
                    }

                    wx = 0 + offsetX;
                    wy = k + offsetY;
                    pAns += bitW.get(wx, wy, wx + k - 1, k2 - 1);
                    if(offsetY != 0 && offsetX == 0) {
                        pAns += bitW.get(0, 0, k - 1, offsetY - 1);
                    } else if(offsetY != 0 && offsetX != 0) {
                        pAns += bitW.get(wx, 0, wx + k - 1, offsetY - 1);
                    }

                    wx = k + offsetX;
                    wy = 0 + offsetY;
                    pAns += bitW.get(wx, wy, k2 - 1, wy + k - 1);
                    if(offsetY == 0 && offsetX != 0) {
                        pAns += bitW.get(0, 0, offsetX - 1, k - 1);
                    } else if(offsetY != 0 && offsetX != 0) {
                        pAns += bitW.get(0, wy, offsetX - 1, wy + k - 1);
                    }

                    ans = Math.max(ans, pAns);
                    // System.err.println(offsetX + "," + offsetY + " = " + ans );
                }
            }

            out.println(ans);
        }

        private static class BIT2D {
            private int[][] B;
            private int     N;

            public BIT2D() {}

            public BIT2D(int n) {
                N = n + 5;
                B = new int[N + 1][N + 1];
            }

            private void update(int i, int j, int val) {
                while(i <= N) {
                    int oj = j;
                    while(oj <= N) {
                        B[i][oj] += val;
                        oj += (oj & -oj);
                    }
                    i += (i & -i);
                }
            }

            private int get(int i, int j) {
                int sum = 0;
                while(i > 0) {
                    int oj = j;
                    while(oj > 0) {
                        sum += B[i][oj];
                        oj -= (oj & -oj);
                    }
                    i -= (i & -i);
                }
                return sum;
            }

            public int get(int x, int y, int nx, int ny) {
                if(nx < x || ny < y)
                    return 0;

                ++x;
                ++y;
                ++nx;
                ++ny;

                return get(nx, ny) - get(nx, y - 1) - get(x - 1, ny) + get(x - 1, y - 1);
            }

            public void update(int x, int y) {
                ++x;
                ++y;
                update(x, y, 1);
            }

        }

    }

    static class Pair<F extends Comparable<F>, S extends Comparable<S>> implements Comparable<Pair<F, S>> {
        public F first;
        public S second;

        public Pair() {}

        public Pair(F first, S second) {
            this.first = first;
            this.second = second;
        }


        public int compareTo(Pair<F, S> fsPair) {
            int cmp = first.compareTo(fsPair.first);
            if(cmp == 0)
                return second.compareTo(fsPair.second);
            return cmp;
        }


        public boolean equals(Object o) {
            if(o == null || o.getClass() != this.getClass())
                return false;
            return compareTo((Pair<F, S>) o) == 0;
        }


        public String toString() {
            return "First: " + first + ", Second: " + second;
        }

    }

    static class FReader {
        private BufferedReader  r;
        private String          line;
        private StringTokenizer st;
        private String          token;

        public FReader() {
            this(System.in);
        }

        public FReader(InputStream i) {
            r = new BufferedReader(new InputStreamReader(i));
        }

        public int nextInt() {
            return Integer.parseInt(nextToken());
        }

        public String next() {
            return nextToken();
        }

        private String peekToken() {
            if(token == null)
                try {
                    while(st == null || !st.hasMoreTokens()) {
                        line = r.readLine();
                        if(line == null) return null;
                        st = new StringTokenizer(line);
                    }
                    token = st.nextToken();
                } catch(IOException e) { }
            return token;
        }

        private String nextToken() {
            String ans = peekToken();
            token = null;
            return ans;
        }

    }
}