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 Rust (1.15.1) (judge verdict: Wrong Answer)

#![allow(unused_imports)]
#![allow(non_snake_case)]

use procon::*;
use std::cmp::{max, min};
use std::collections::*;
use std::ops::*;
use std::*;

#[derive(PartialEq, Clone, Copy, Debug)]
enum Color {
    B,
    W,
}

pub fn main() {
    let (_, k, w, board) = {
        let words = read_words::<usize>();
        let (N, K) = (words[0], words[1]);
        let w = K * 2;

        // board[y][x] = d: score +d if black
        let mut board = vec![vec![0_i32; w]; w];

        for _ in 0..N {
            let words = read_words::<String>();
            let (x, y, c) = (
                words[0].parse::<i32>().unwrap(),
                words[1].parse::<i32>().unwrap(),
                if words[2] == "B" { Color::B } else { Color::W },
            );

            let W = w as i32;
            let y = ((y % W + W) % W) as usize;
            let x = ((x % W + W) % W) as usize;

            board[y][x] += if c == Color::B { 1 } else { -1 };
        }
        (N, K, w, board)
    };

    // let transposed = {
    //     let mut t = vec![vec![0; w]; w];
    //     for y in 0..w {
    //         for x in 0..w {
    //             t[(w - x) % w][y] = board[y][x];
    //         }
    //     }
    //     t
    // };

    let mut score = 0;
    let mut up = vec![vec![0_i32; w]; w];
    let mut uy = vec![0_i32; w];
    let mut ux = vec![0_i32; w];
    for y in 0..w {
        for x in 0..w {
            let d = board[y][x];

            // 黒なら初期状態で貢献
            let black = (y < k) == (x < k);
            let d = if black { d } else { -d };

            // 色が一致していればプラス
            if d > 0 {
                score += d;
            }

            let ty = y % k;
            let tx = x % k;

            // 模様が右に (tx + 1) シフトしたら貢献が消える (スコアが減る)、
            // さらに k シフトしたら再び貢献する
            {
                ux[(tx + 1) % w] -= d;
                ux[(tx + 1 + k) % w] += d;
            }

            {
                uy[(ty + 1) % w] -= d;
                uy[(ty + 1 + k) % w] += d;
            }

            // 模様が上に (ty + 1) シフトしたら色が変わって貢献が逆転する、
            // さらに k シフトしたら戻る
            {
                up[(ty + 1) % w][(tx + 1) % w] += 2 * d;
                up[(ty + 1) % w][(tx + 1 + k) % w] -= 2 * d;

                up[(ty + 1 + k) % w][(tx + 1) % w] -= 2 * d;
                up[(ty + 1 + k) % w][(tx + 1 + k) % w] += 2 * d;
            }
        }
    }

    // println!("score={}", score);
    // println!("uy={:?}", uy);

    let mut max_score = score;
    let mut sy = score;

    for dy in 0..w {
        let mut sx = sy;

        for dx in 0..w {
            max_score = max(max_score, sx);

            sx += ux[(dx + 1) % w];
        }

        for dx in 0..w {
            ux[dx] += up[(dy + 1) % w][dx];
        }

        sy += uy[(dy + 1) % w];
    }

    println!("{}", max_score);
    return;
}

pub mod procon {
    use std;
    use std::collections::*;
    use std::io;
    use std::mem;
    use std::str::FromStr;

    pub fn read_line() -> String {
        let mut buf = String::new();
        io::stdin().read_line(&mut buf).unwrap();
        buf.trim_right().to_owned()
    }

    pub fn read_words<T>() -> Vec<T>
    where
        T: std::str::FromStr,
        T::Err: std::fmt::Debug,
    {
        let mut buf = String::new();
        io::stdin().read_line(&mut buf).unwrap();
        buf.split_whitespace()
            .map(|word| T::from_str(word).unwrap())
            .collect()
    }

    pub fn read_vec(len: usize) -> Vec<String> {
        let mut vec = Vec::new();
        while vec.len() < len {
            let line = read_line();
            for word in line.split_whitespace() {
                vec.push(word.to_owned());
            }
        }
        assert!(vec.len() == len);
        vec
    }
}