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-----
4 3
0 1 W
1 2 W
5 3 B
5 4 B

-----Sample Output-----
4

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

Difficulty: interview

Starter code:

Solutions:
#!/usr/bin/env python3
# coding=utf-8

import sys

import numpy as np

n, k = list(map(int, sys.stdin.readline().strip().split(" ")))
xyc = [l.strip().split(" ") for l in sys.stdin.readlines()]
xy = [(int(_x) % (2 * k), int(_y) % (2 * k) if _c == "W" else (int(_y) + k) % (2 * k))
      for (_x, _y, _c) in xyc]

# ans = np.zeros((2 * k, 2 * k), dtype=np.int32)
ans = [[0 for j in range(2 * k + 1)] for i in range(2 * k + 1)]
for _x, _y in xy:
    if (_x - k + 0.5) * (_y - k + 0.5) > 0:
        _x %= k
        _y %= k
        ans[_x][_y] += 2
        ans[_x + k][_y] -= 2
        ans[_x][_y + k] -= 2
        ans[_x + k][_y + k] += 2
        ans[_x + k][0] += 1
        ans[0][_y + k] += 1
        ans[0][0] += 1
        ans[_x][0] -= 1
        ans[0][_y] -= 1
    else:
        _x %= k
        _y %= k
        ans[_x][_y] -= 2
        ans[_x + k][_y] += 2
        ans[_x][_y + k] += 2
        ans[_x + k][_y + k] -= 2
        ans[_x + k][0] -= 1
        ans[0][_y + k] -= 1
        ans[_x][0] += 1
        ans[0][_y] += 1
print((np.asarray(ans).cumsum(axis=1).cumsum(axis=0).max()))


import sys

#縦k、横kのマスに移動させて考える
n, k = map(int, sys.stdin.readline().strip().split())
x = []
y = []
mx = []
my = []
for _ in range(n):
    xx, yy, c = sys.stdin.readline().strip().split()
    xx = int(xx)
    yy = int(yy)
    if c == 'W':
        xx += k
    xx %= 2 * k
    yy %= 2 * k
    if xx >= k:
        if yy >= k:
            x.append(xx - k)
            y.append(yy - k)
        else:
            mx.append(xx - k)
            my.append(yy)
    else:
        if yy >= k:
            mx.append(xx)
            my.append(yy - k)
        else:
            x.append(xx)
            y.append(yy)

graph = [[0 for _ in range(k)] for __ in range(k)]

#累積和
#lx + lmx = n
lx = len(x)
graph[0][0] += lx
for i in range(lx):
    graph[x[i]][0] -= 1
    graph[0][y[i]] -= 1
    graph[x[i]][y[i]] += 2

lmx = len(mx)
graph[0][0] -= lmx
for i in range(lmx):
    graph[mx[i]][0] += 1
    graph[0][my[i]] += 1
    graph[mx[i]][my[i]] -= 2

for i in graph:
    for j in range(k-1):
        i[j+1] += i[j]

for i in range(k):
    for j in range(k-1):
        graph[j+1][i] += graph[j][i]

#最大値、最小値を取得
big = max([max(i) for i in graph]) + lmx
small = min([min(i) for i in graph]) - lx

if big + small >= 0:
    print(big)
else:
    print(-small)

n, k = map(int, input().split())
favor = [tuple(input().split()) for _ in range(n)]
square = [[0 for _ in range(k)] for _ in range(k)]
initscore = 0
for xc, yc, c in favor:
    x = int(xc)
    y = int(yc)
    x %= 2*k
    y %= 2*k
    if (x in range(k) and y in range(k)) or (x in range(k, 2*k) and y in range(k, 2*k)):
        if c == 'B':
            square[x%k][y%k] += 1
        else:
            square[x%k][y%k] -= 1
            initscore += 1
    else:
        if c == 'B':
            square[x%k][y%k] -= 1
            initscore += 1
        else:
            square[x%k][y%k] += 1
cum = [[0 for _ in range(k+1)] for _ in range(k+1)]
for i in range(k):
    for j in range(k):
        cum[i+1][j+1] = cum[i+1][j] + cum[i][j+1] - cum[i][j] + square[i][j]
maxscore = 0
for i in range(k):
    for j in range(k):
        score = cum[i][k] + cum[k][j] - 2*cum[i][j]
        maxscore = max(maxscore, max(cum[k][k] - score, score))
print(maxscore + initscore)

import numpy as np
N, K, *XYC = open(0).read().split()
N = int(N)
K = int(K)
board = np.zeros((4 * K + 1, 4 * K + 1), dtype=np.int64)
for x, y, c in zip(XYC[::3], XYC[1::3], XYC[2::3]):
    x = int(x)
    y = int(y)
    if c == 'W':
        x += K
    x = x % (2 * K)
    y = y % (2 * K)
    board[x, y] += 1
    board[(x + K) % (2 * K), (y + K) % (2 * K)] += 1
board[1 + 2 * K:, 1 + 2 * K:] = board[:2 * K, :2 * K]
board[1:1 + 2 * K, 1 + 2 * K:] = board[1 + 2 * K:, 1 + 2 * K:]
board[1 + 2 * K:, 1:1 + 2 * K] = board[1 + 2 * K:, 1 + 2 * K:]
board[1:1 + 2 * K, 1:1 + 2 * K] = board[1 + 2 * K:, 1 + 2 * K:]
board[0, :] = 0
board[:, 0] = 0
for j in range(1, 3 * K):
    board[:, j] += board[:, j - 1]
for j in range(1, 3 * K):
    board[j, :] += board[j - 1, :]
ans = np.max(board[K:3 * K, K:3 * K] + board[:2 * K, :2 * K] -
             board[:2 * K, K:3 * K] - board[K:3 * K, :2 * K])
print(ans)


from subprocess import*
call(('julia','-e',"""
const lines=readlines()
input()=shift!(lines)
int(s)=parse(Int32,s)
intLine()=map(int,split(input()))
function nextLine(k)
    x,y,c=split(input())
    int(x)%2k+1,(int(y)+(c=="W")k)%2k+1
end
function solve(k,g)
    m=0
    for i=1:2k,j=1:2k
        a=0
        for x=-1:2,y=-1:2
            (x+y)%2!=0&&continue
            v,w=i+x*k,j+y*k
            v>0<w&&(a+=g[min(2k,v)][min(2k,w)])
            v>k&&w>0&&(a-=g[min(2k,v-k)][min(2k,w)])
            w>k&&v>0&&(a-=g[min(2k,v)][min(2k,w-k)])
            v>k<w&&(a+=g[min(2k,v-k)][min(2k,w-k)])
        end
        m=max(m,a)
    end
    m
end
function main()
    n,k=intLine()
    g=Array{Int32,1}[[0for j=1:2k]for i=1:2k]
    for i=1:n
        x,y=nextLine(k)
        g[x][y]+=1
    end
    println(solve(k,cumsum(map(cumsum,g))))
end
main()
"""))

N,K = list(map(int,input().split()))
cum = [[0]*(2*K+1) for i in range(2*K+1)]

def vertex(z):
    if z < K:
        return [(0,z+1),(z+K+1,2*K)]
    else:
        return [(z-K+1,z+1)]

for i in range(N):
    x,y,c = input().split()
    x = int(x)
    y = int(y)
    x %= 2*K
    if c == 'B':
        y %= 2*K
    else:
        y += K
        y %= 2*K

    for d in [0,K]:
        for b,t in vertex((y+d)%(2*K)):
            for l,r in vertex((x+d)%(2*K)):
                cum[b][l] += 1
                cum[t][r] += 1
                cum[b][r] -= 1
                cum[t][l] -= 1

import numpy as np
cum = np.array(cum)
print((np.cumsum(np.cumsum(cum,axis=0),axis=1).max()))


# D - Checker

N, K = map(int, input().split())
g = [[0]*K for _ in range(K)] # PDF解説通り2K*2K範囲でやると市松模様の処理が大変なのでK*Kの範囲で計算

for _ in range(N):
    x, y, c = input().split()
    x = int(x)
    y = int(y)
    tmp = (x//K + y//K) % 2
    x %= K
    y %= K
    if (tmp == 0 and c == "B") or (tmp == 1 and c == "W"):
        g[x][y] += 1
    else:
        g[x][y] -= 1 # 白希望の点を-1で記録する

for i in range(K):
    for j in range(1,K):
        g[i][j] += g[i][j-1]

for i in range(1,K):
    for j in range(K):
        g[i][j] += g[i-1][j]

# [i,j]を黒範囲の左下の点とする。[0,i] * [0,j] の範囲または[i+1,K-1] * [j+1,K-1]の範囲にある黒希望点の個数を足し、白希望の点の個数を引く
# 上記範囲外にある白希望の点の個数を足し、黒希望の点の個数を引く
ans = 0
for i in range(K):
    for j in range(K):
        n_satisfied = g[-1][-1] -2*(g[-1][j] + g[i][-1]) + 4*g[i][j]
        ans = max(ans, (N + n_satisfied)//2, (N - n_satisfied)//2) # ((希望通りの点 + 希望通りでない点) + (希望通りの点 - 希望通りでない点))//2

print(ans)

import numpy as np

def getBoundary(p, k, k2):
    if p - k + 1 >= 0:
        return [(p - k + 1, p + 1)]
    else:
        return [(0, p + 1), ((p - k + 1) % k2, k2)]

n, k = list(map(int, input().strip().split()))
k2 = k * 2
b = [[0 for i in range(k2 + 1)] for j in range(k2 + 1)]

for i in range(n):
    x_str, y_str, c_str = input().strip().split()
    x = int(x_str) % k2
    y = (int(y_str) + (c_str == 'B') * k) % k2
    for xb, xe in getBoundary(x % k2, k, k2):
        for yb, ye in getBoundary(y % k2, k, k2):
            b[xb][yb] += 1
            b[xb][ye] -= 1
            b[xe][yb] -= 1
            b[xe][ye] += 1
    for xb, xe in getBoundary((x + k) % k2, k, k2):
        for yb, ye in getBoundary((y + k) % k2, k, k2):
            b[xb][yb] += 1
            b[xb][ye] -= 1
            b[xe][yb] -= 1
            b[xe][ye] += 1

arr_b = np.array(b)
for i in range(k2):
    arr_b[i + 1] += arr_b[i]
for j in range(k2):
    arr_b[:, j + 1] += arr_b[:, j]
print((arr_b.max()))


import numpy as np
N, K = list(map(int, input().split()))
ub = K * 2
b = [[0 for j in range(ub + 1)] for i in range(ub + 1)]
ADD = {"B": 0, "W": K}


def create_bound(p, K, ub):
    if p - K + 1 >= 0:
        return [(p - K + 1, p + 1)]
    else:
        return [(0, p + 1), ((p - K + 1) % ub, ub)]


for i in range(N):
    x, y, c = input().split()
    nx = int(x) % ub
    ny = (int(y) + ADD[c]) % ub
    for add in [0, K]:
        for xlb, xub in create_bound((nx + add) % ub, K, ub):
            for ylb, yub in create_bound((ny + add) % ub, K, ub):
                b[xlb][ylb] += 1
                b[xlb][yub] -= 1
                b[xub][ylb] -= 1
                b[xub][yub] += 1

b_arr = np.array(b)
for i in range(ub):
    b_arr[i + 1, :] += b_arr[i, :]
for j in range(ub):
    b_arr[:, j + 1] += b_arr[:, j]
print((b_arr.max()))


n, k = map(int, input().split())
s = [[0] * k for _ in range(2 * k + 1)]
for _ in range(n):
    x, y, c = input().split()
    x, y = int(x), int(y)
    x -= (x // (2 * k)) * (2 * k)
    y -= (y // (2 * k)) * (2 * k)
    if x >= k and y >= k:
        x -= k
        y -= k
    elif y >= k:
        x += k
        y -= k
    if c == "B":
        if x >= k:
            x -= k
        else:
            x += k
    s[x + 1][y] += 1
for i in range(2 * k):
    for j in range(k):
        s[i + 1][j] += s[i][j]
ans = 0
for i in range(k):
    cnt = 0
    for j in range(k):
        cnt += (s[i + k][j] - s[i][j])
    ans = max(ans, cnt, n - cnt)
    for j in range(k):
        cnt -= (2 * (s[i + k][j] - s[i][j]))
        cnt += s[2 * k][j]
        ans = max(ans, cnt, n - cnt)
print(ans)

from numpy import*
N,K=map(int,input().split())
m=zeros((3*K,3*K),dtype=int)
L=2*K
o=0
for _ in [0]*N:
 x,y,c=input().split()
 x,y=int(x)%L,int(y)%L
 t=c=='W'
 m[x,y]+=2*t-1
 o+=t
for _ in [0,0]:
 m[L:]=m[:K]
 m=cumsum(m,axis=0)
 m[:L]-=m[K:]
 m=m.T
m=m[:L,:L]
print(o-int((m+roll(roll(m,K,axis=0),K,axis=1)).min()))

import sys
import numpy as np
from collections import Counter

read = sys.stdin

N, K = list(map(int, read.readline().split()))
k = 2 * K
xyc = np.array(read.read().split(), np.str).reshape(-1, 3)
x = xyc[:, 0].astype(int)
y = xyc[:, 1].astype(int)
c = xyc[:, 2]

x = np.where(c == 'B', x - K, x)
x %= k
y %= k

'''
# grid[[1,2],[1,2]]+=1 としてもgrid[1,2]=1であり重複は考慮されない。
# uniqueを使って(x,y)の重複をカウントする
# return_countはver1.9からだった・・・ ダメじゃん
xy, cnt = np.unique(x + y * 10000, return_counts=True)
x = xy % 10000
y = xy // 10000
'''
xy = Counter(list(zip(x, y)))
cnt = np.array(list(xy.values()), np.int64)
xy = np.array(list(xy.keys()), np.int64)
x = xy[:, 0]
y = xy[:, 1]

grid = np.zeros((3 * K, 3 * K), np.int64)
grid[x, y] += cnt
grid[x + K, y + K] += cnt
grid[x + K, y] -= cnt
grid[x, y + K] -= cnt
np.cumsum(grid, axis=0, out=grid)
np.cumsum(grid, axis=1, out=grid)

p1 = grid[:K, :K] + grid[k:, k:] + grid[K:k, K:k] + grid[k:, :K] + grid[:K, k:]
p2 = grid[K:k, :K] + grid[K:k, k:] + grid[:K, K:k] + grid[k:, K:k]
print((max(p1.max(), p2.max())))


import numpy as np
N, K = list(map(int, input().split()))
mod = 2*K
field = [[0]*(2*K+1) for _ in range(2*K+1)]

def gen_pattern(x):
    if x < K-1:
        return [[0, x+1], [x+K+1, 2*K]]
    else:
        return [[x-K+1, x+1]]

for _ in range(N):
    x, y, c = input().split()
    x, y = int(x), int(y)
    if c == 'W':
        y += K
    x %= mod
    y %= mod
    for tmp in [0, K]:
        for l, r in gen_pattern((x+tmp) % mod):
            for b, t in gen_pattern((y+tmp) % mod):
                field[l][b] += 1
                field[l][t] -= 1
                field[r][b] -= 1
                field[r][t] += 1

print((np.max(np.cumsum(np.cumsum(field, axis=0), axis=1))))


import numpy as np
import io

nime, mike = map(int, input().split())
mod = 2*mike
array = [[0]*(2*mike+1) for _ in range(2*mike+1)]

def gen_pattern(x):
    if x < mike-1:
        return [[0, x+1], [x+mike+1, 2*mike]]
    else:
        return [[x-mike+1, x+1]]

for _ in range(nime):
    x, y, c = input().split()
    x, y = int(x), int(y)
    if c == 'W':
        y += mike
    x %= mod
    y %= mod
    for tmp in [0, mike]:
        for l, r in gen_pattern((x+tmp) % mod):
            for b, t in gen_pattern((y+tmp) % mod):
                array[l][b] += 1
                array[l][t] -= 1
                array[r][b] -= 1
                array[r][t] += 1
print(np.max(np.cumsum(np.cumsum(array, axis=0), axis=1)))

import numpy as np
 
N,K=map(int, input().split())
p=[list(input().split()) for _ in range(N)]
grid = [[[0]*2 for j in range(K)] for i in range(K)]

for i in range(N):
  x, y, c = p[i]
  x, y = int(x), int(y)
  mx, my = x%K, y%K
  f = False
  if (x//K)%2 != (y//K)%2:
    f = not f
  if c == "W":
    f = not f
  if f:
    grid[0][0][0] += 1
    grid[mx][0][0] -= 1
    grid[0][my][0] -= 1
    grid[mx][my][0] += 2
  else:
    grid[0][my][0] += 1
    grid[mx][0][0] += 1
    grid[mx][my][0] -= 2
  f = False
  if (x//K)%2 != (y//K)%2:
    f = not f
  if c == "B":
    f = not f
  if f:
    grid[0][0][1] += 1
    grid[mx][0][1] -= 1
    grid[0][my][1] -= 1
    grid[mx][my][1] += 2
  else:
    grid[0][my][1] += 1
    grid[mx][0][1] += 1
    grid[mx][my][1] -= 2
grid = np.array(grid)
grid = np.cumsum(grid, axis=0)
grid = np.cumsum(grid, axis=1)
print(int(np.max(grid)))

n, k = map(int, input().split())

xy = []
F = [[0]*(2*k+1) for _ in range(2*k+1)]
for __ in range(n):
    x, y, c = input().split()
    x, y = int(x), int(y)
    if c == 'B':
        y += k
    x %= 2*k
    y %= 2*k

    for _ in range(2):
        x = (x+k)%(2*k)
        y = (y+k)%(2*k)
        #右上
        F[y+1][x+1] += 1
        if x-k >= 0 and y-k >= 0:
            #普通の左上と左上右下
            F[y+1][x-k+1] -= 1
            F[y-k+1][x+1] -= 1
            F[y-k+1][x-k+1] += 1
        elif y-k >= 0:
            #特殊な左
            F[y-k+1][0] += 1
            F[y+1][0] -= 1
            F[y-k+1][x+1] -= 1
            #特殊な左上と左下
            F[y-k+1][x+k+1] += 1
            F[y+1][x+k+1] -= 1
        elif x-k >= 0:
            F[0][x-k+1] += 1
            F[0][x+1] -= 1
            F[y+1][x-k+1] -= 1

            F[y+k+1][x-k+1] += 1
            F[y+k+1][x+1] -=1
        else:
            F[0][x+1] -= 1
            F[y+1][0] -= 1
            F[0][0] += 1
            #左上
            F[y+k+1][0] += 1
            F[y+k+1][x+1] -= 1
            #右下
            F[0][x+k+1] += 1
            F[y+1][x+k+1] -= 1
            #右上
            F[y+k+1][x+k+1] += 1
    if __ == 0:
        pass
        # break
ans = 0
m = 3

from numpy import array
F = array(F)
for i in range(0, 2*k):
    F[:, i+1] += F[:, i]
for i in range(0, 2*k):
    F[i+1, :] += F[i, :]
print(F[:2*k, :2*k].max())

import numpy as np


def solve(string):
    n, k, *xyc = string.split()
    k = int(k)
    l = 2 * int(k)
    xy = [(int(x) % l, int(y) % l) if c == "W" else (int(x) % l, (int(y) + k) % l)
          for x, y, c in zip(xyc[::3], xyc[1::3], xyc[2::3])]
    ans = [[0 for j in range(l + 0)] for i in range(l + 0)]
    for _x, _y in xy:
        if (_x - k + 0.5) * (_y - k + 0.5) > 0:
            _x %= k
            _y %= k
            ans[_x][_y] += 2
            ans[_x + k][_y] -= 2
            ans[_x][_y + k] -= 2
            ans[_x + k][_y + k] += 2
            ans[_x + k][0] += 1
            ans[0][_y + k] += 1
            ans[0][0] += 1
            ans[_x][0] -= 1
            ans[0][_y] -= 1
        else:
            _x %= k
            _y %= k
            ans[_x][_y] -= 2
            ans[_x + k][_y] += 2
            ans[_x][_y + k] += 2
            ans[_x + k][_y + k] -= 2
            ans[_x + k][0] -= 1
            ans[0][_y + k] -= 1
            ans[_x][0] += 1
            ans[0][_y] += 1
    return str(np.asarray(ans).cumsum(axis=1).cumsum(axis=0).max())


def __starting_point():
    n, m = list(map(int, input().split()))
    print((solve('{} {}\n'.format(n, m) + '\n'.join([input() for _ in range(n)]))))

__starting_point()

N, K = map(int, input().split())
import numpy as np
#対称性を利用して点を単位格子K*2Kに圧縮
_2K, _4K = 2*K, 4*K
shape = (_2K+1,_4K+1) #後でK*2Kに圧縮
Grd = np.zeros(shape,dtype='int64')
for _ in range(N):
    x, y, c = input().split()
    x, y = int(x), int(y)
    if c == 'B':
        x, y = x%_2K, y%_2K
    else: 
        x, y = (x+K)%_2K, y%_2K
    #点について、2K*2K -> K*2Kの調整。次は等価、(K+i,K+j)==(i,j),(i,K+j)==(i+K,j)
    if x >= K and y >= K: x -= K; y -= K
    if x < K and y >= K: x += K; y -= K
    #この点がK*Kの黒色正方形内に入る。正方形を特徴づけるには左下の座標だけで十分。
    #⇒１つの点はK**2個の塗り方に+1の影響を与える。
    #毎回2K**2のマスにアクセスするとTLEするため、あとで累積和(計算量O(K**2))を取った時に+1される範囲が等しくなるように調整する(隣接差分を取る)。
    #K=3の場合
    #[[1 1 1 0 0 0]    [[ 1 0 0 -1 0 0  0]
    # [1 1 1 0 0 0]     [ 0 0 0  0 0 0  0]
    # [1 1 1 0 0 0]  => [ 0 0 0  0 0 0  0]
    # [0 0 0 0 0 0]     [-1 0 0  1 0 0  0]
    # [0 0 0 0 0 0]     [ 0 0 0  0 0 0  0]
    # [0 0 0 0 0 0]]    [ 0 0 0  0 0 0  0]
    #                   [ 0 0 0  0 0 0  0]
    
    Grd[y, x] += 1
    Grd[y+K, x+K] += 1
    Grd[y+K, x] += -1
    Grd[y, x+K] += -1
del x, y, c

#2重累積和計算
Grd = Grd.cumsum(axis=1).cumsum(axis=0)
#2K*4K -> K*2Kへ圧縮
Grd = Grd[:,:_2K] +Grd[:,_2K:_4K]
Grd = Grd[:K,:] +np.concatenate((Grd[K:_2K,K:_2K],Grd[K:_2K,:K]),axis=1) 

ans = Grd.max()
print(ans)

import sys
import numpy as np
def main():
    input = sys.stdin.readline
    def gen_pattern(x):
        if x < K-1:
            return [[0, x+1], [x+K+1, 2*K]]
        else:
            return [[x-K+1, x+1]]
    def inputs():
        return [int(x) for x in input().split()]
    def inputstr():
        return list(input().split())
    N,K = inputs()
    BB = [[0]*(2*K+1) for _ in range(2*K+1)]
    for i in range(N):
        x,y,c = inputstr()
        if c=="W":
            y = int(y)+K
        x = int(x)%(2*K)
        y = int(y)%(2*K)
        #BB[x,y] += 1
        for shift in [0,K]:
            for b,t in gen_pattern((y+shift)%(2*K)):
                for l,r in gen_pattern((x+shift)%(2*K)):
                    BB[b][l] +=1
                    BB[b][r] -=1
                    BB[t][l] -=1
                    BB[t][r] +=1
    ans = (np.max(np.cumsum(np.cumsum(BB, axis=1), axis=0)))
    #print(BB)
    print((int(ans)))
main()


import numpy as np
N, K = list(map(int, input().split()))
ub = K * 2
b = [[0 for j in range(ub + 1)] for i in range(ub + 1)]
ADD = {"B": 0, "W": K}

def create_bound(p, K, ub):
	if p - K + 1 >= 0:
		return [(p - K + 1, p + 1)]
	else:
		return [(0, p + 1), ((p - K + 1) % ub, ub)]

for i in range(N):
	x, y, c = input().split()
	nx = int(x) % ub
	ny = (int(y) + ADD[c]) % ub
	for add in [0, K]:
		for xlb, xub in create_bound((nx + add) % ub, K, ub):
			for ylb, yub in create_bound((ny + add) % ub, K, ub):
				b[xlb][ylb] += 1
				b[xlb][yub] -= 1
				b[xub][ylb] -= 1
				b[xub][yub] += 1

b_arr = np.array(b)
for i in range(ub):
	b_arr[i + 1, :] += b_arr[i, :]
for j in range(ub):
	b_arr[:, j + 1] += b_arr[:, j]
print((b_arr.max()))


import numpy as np

N, K = list(map(int, input().split()))
B = np.zeros((2 * K, 2 * K), np.int32)

for _ in range(N):
    x, y, c = input().split()
    if c == "B":
        B[int(x) % (2 * K)][int(y) % (2 * K)] += 1
    else:
        B[int(x) % (2 * K)][(int(y) + K) % (2 * K)] += 1

SB = np.zeros((4 * K + 1, 4 * K + 1), np.int32)

SB[0*K+1:2*K+1, 0*K+1:2*K+1] = B
SB[0*K+1:2*K+1, 2*K+1:4*K+1] = B
SB[2*K+1:4*K+1, 0*K+1:2*K+1] = B
SB[2*K+1:4*K+1, 2*K+1:4*K+1] = B

np.cumsum(SB, 0, out=SB)
np.cumsum(SB, 1, out=SB)

ans = 0
cand = SB[1*K:3*K+1, 1*K:3*K+1].copy()
cand -= SB[0*K:2*K+1, 1*K:3*K+1]
cand -= SB[1*K:3*K+1, 0*K:2*K+1]
cand += SB[0*K:2*K+1, 0*K:2*K+1]
cand += SB[2*K:4*K+1, 2*K:4*K+1]
cand -= SB[1*K:3*K+1, 2*K:4*K+1]
cand -= SB[2*K:4*K+1, 1*K:3*K+1]
cand += SB[1*K:3*K+1, 1*K:3*K+1]
ans = np.max(cand)

print(ans)


import numpy as np

N, K = map(int, input().split())
K2 = 2 * K
Mij = [[0 for _ in range(K2 + 1)] for _ in range(K2 + 1)]


def imos(x1, y1, x2, y2):
    Mij[y1][x1] += 1
    Mij[y2][x2] += 1
    Mij[y2][x1] -= 1
    Mij[y1][x2] -= 1

for _ in range(N):
    ls = input().split()
    x = int(ls[0]) % K2
    y = int(ls[1]) % K2
    if ls[2] == "B":
        y = (y + K) % K2
    x_ = x % K
    y_ = y % K

    if (x < K and y < K) or (K <= x and K <= y):
        imos(0, 0, x_ + 1, y_ + 1)
        imos(x_ + K + 1, 0, K2, y_ + 1)
        imos(0, y_ + K + 1, x_ + 1, K2)
        imos(x_ + K + 1, y_ + K + 1, K2, K2)
        imos(x_ + 1, y_ + 1, x_ + K + 1, y_ + K + 1)
    else:
        imos(x_ + 1, 0, x_ + K + 1, y_ + 1)
        imos(x_ + 1, y_ + K + 1, x_ + K + 1, K2)
        imos(0, y_ + 1, x_ + 1, y_ + K + 1)
        imos(x_ + K + 1, y_ + 1, K2, y_ + K + 1)

Mij = np.array(Mij)
for x in range(K2):
    Mij[:, x + 1] += Mij[:, x]
for y in range(K2):
    Mij[y + 1, :] += Mij[y, :]

print(Mij.max())

n,k = map(int, input().split())
g = [[0]*(k+1) for _ in range(k+1)]
ans,b = 0,0
for _ in range(n):
  x,y,c = input().split()
  x,y = int(x), int(y)
  d = x//k + y//k
  x %= k; y %= k
  if (c == 'W') ^ (d%2):
    g[x+1][y+1] += 1
  else:
    g[x+1][y+1] -= 1
    b += 1
for i in range(k):
  for j in range(k):
    g[i+1][j+1] += g[i][j+1] + g[i+1][j] - g[i][j]
for i in range(k):
  for j in range(k):
    cur = g[k][k] - g[k][j] - g[i][k] + g[i][j]*2 + b
    if cur > ans: ans = cur
    if n-cur > ans: ans = n-cur
print(ans)

# python 3.4.3
import sys
input = sys.stdin.readline
import numpy as np

# -------------------------------------------------------------
# function
# -------------------------------------------------------------
def sum2d(i1,j1,i2,j2):
    A[i1][j1] += 1
    A[i1][j2] -= 1
    A[i2][j1] -= 1
    A[i2][j2] += 1


# -------------------------------------------------------------
# main
# -------------------------------------------------------------
N,K = list(map(int,input().split()))
XYC = [list(input().split()) for _ in range(N)]

A = [[0 for _ in range(K*2+1)] for _ in range(K*2+1)]

for x,y,c in XYC:
    # 白はそのまま, 黒はx軸方向にKずらして白として扱う
    i = (int(x) if c=="W" else int(x)+K) % (K*2)
    j = int(y) % (K*2)
    i0 = i%K
    j0 = j%K

    # 分割区画の左下が白の場合 (白は5箇所)
    #   a * b
    #   * c *
    #   d * e
    if (i<K and j<K) or (i>=K and j>=K):
        sum2d(0,0,i0,j0) # (a)左上
        sum2d(i0+K,0,K*2,j0) # (b)右上
        sum2d(i0,j0,i0+K,j0+K) # (c)真ん中
        sum2d(0,j0+K,i0,K*2) # (d)左下
        sum2d(i0+K,j0+K,K*2,K*2) # (e)右下

    # 分割区画の左下が黒の場合 (白は4箇所)
    #   * a *
    #   b * c
    #   * d *
    else:
        sum2d(i0,0,i0+K,j0) # (a)上
        sum2d(0,j0,i0,j0+K) # (b)左
        sum2d(i0+K,j0,K*2,j0+K) # (c)右
        sum2d(i0,j0+K,i0+K,K*2) # (d)下
 
# 2次元累積和
AA = np.array(A)
for i in range(K*2):
    AA[i+1, :] += AA[i, :]
for j in range(K*2):
    AA[:, j+1] += AA[:, j]
 
print((AA.max()))


n, k = map(int, input().split())
X, Y, C = [], [], []
for _ in range(n):
  x, y, c = input().split()
  X.append(int(x)%(2*k))
  Y.append(int(y)%(2*k))
  C.append(c=="B")
G = [[0]*k for _ in range(k)]
cnt = 0
for x, y, c in zip(X, Y, C):
  if (x >= k and y < k) or (x < k and y >= k):
    x += k
    c ^= 1
  x %= k
  y %= k
  G[x][y] += (-1)**c
  cnt += c
for i in range(k):
  for j in range(k-1):
    G[i][j+1] += G[i][j]
for j in range(k):
  for i in range(k-1):
    G[i+1][j] += G[i][j]
ans = 0
for i in range(k):
  for j in range(k):
    temp = G[k-1][k-1] - G[i][k-1] - G[k-1][j] + G[i][j]*2 + cnt
    ans = max(ans, temp, n-temp)
print(ans)

import sys
import numpy as np
from collections import Counter

read = sys.stdin

N, K = list(map(int, read.readline().split()))
k = 2 * K
xyc = np.array(read.read().split(), np.str).reshape(-1, 3)
x = xyc[:, 0].astype(int)
y = xyc[:, 1].astype(int)
c = xyc[:, 2]

x[c == 'B'] -= K
x %= k
y %= k

'''
# grid[[1,1],[2,2]]+=1 としてもgrid[1,2]=1であり重複は考慮されない。
# uniqueを使って(x,y)の重複をカウントする
# return_countはver1.9からだった・・・ ダメじゃん
xy, cnt = np.unique(x + y * 10000, return_counts=True)
x = xy % 10000
y = xy // 10000
'''
xy = Counter(list(zip(x, y)))
cnt = np.array(list(xy.values()), np.int64)
xy = np.array(list(xy.keys()), np.int64)
x = xy[:, 0]
y = xy[:, 1]

grid = np.zeros((3 * K, 3 * K), np.int64)
grid[x, y] += cnt
grid[x + K, y + K] += cnt
grid[x + K, y] -= cnt
grid[x, y + K] -= cnt
np.cumsum(grid, axis=0, out=grid)
np.cumsum(grid, axis=1, out=grid)

p1 = grid[:K, :K] + grid[k:, k:] + grid[K:k, K:k] + grid[k:, :K] + grid[:K, k:]
p2 = grid[K:k, :K] + grid[K:k, k:] + grid[:K, K:k] + grid[k:, K:k]
print((max(p1.max(), p2.max())))


N, K = map(int, input().split())
import numpy as np
#対称性を利用して点を単位格子K*2Kに圧縮
_2K, _4K = 2*K, 4*K
shape = (_2K,_4K) #後でK*2Kに圧縮
Grd = np.zeros(shape, dtype='int64')
for _ in range(N):
    x, y, c = input().split()
    x, y = int(x), int(y)
    if c == 'B':
        x, y = x%_2K, y%_2K
    else: 
        x, y = (x+K)%_2K, y%_2K
    #点について、2K*2K -> K*2Kの調整。次は等価、(K+i,K+j)と(i,j),(i,K+j)と(i+K,j)
    if x >= K and y >= K: x -= K; y -= K
    if x < K and y >= K: x += K; y -= K
    #この点がK*Kの黒色正方形内に入る。正方形を特徴づけるには頂点の座標１つだけで十分。
    #⇒１つの点はK*K個の塗り方に+1の影響を与える。
    #毎回K**2のマスにアクセスするとTLEするため、後で累積和(計算量O(K**2))を取った時に+1される範囲が等しくなるように調整する(隣接差分を取る)。
    #K=3の場合
    #[[1 1 1 0 0 0]    [[ 1 0 0 -1 0 0 0]
    # [1 1 1 0 0 0]     [ 0 0 0  0 0 0 0]
    # [1 1 1 0 0 0]  => [ 0 0 0  0 0 0 0]
    # [0 0 0 0 0 0]     [-1 0 0  1 0 0 0]
    # [0 0 0 0 0 0]     [ 0 0 0  0 0 0 0]
    # [0 0 0 0 0 0]]    [ 0 0 0  0 0 0 0]
    #                   [ 0 0 0  0 0 0 0]
    
    Grd[y, x] += 1
    Grd[y+K, x+K] += 1
    Grd[y+K, x] += -1
    Grd[y, x+K] += -1
del x, y, c

#2重累積和計算
Grd = Grd.cumsum(axis=1).cumsum(axis=0)
#2K*4K -> K*2Kへ圧縮
Grd = Grd[:,:_2K] +Grd[:,_2K:_4K]
Grd = Grd[:K,:] +np.concatenate((Grd[K:_2K,K:_2K],Grd[K:_2K,:K]),axis=1) 

ans = Grd.max()
print(ans)

import numpy as np
N, K = list(map(int, input().split()))
mod = 2*K
#field = np.zeros((2*K+1, 2*K+1), dtype='i')
field = [[0]*(2*K+1) for _ in range(2*K+1)]

def gen_pattern(x):
    if x < K-1:
        return [[0, x+1], [x+K+1, 2*K]]
    else:
        return [[x-K+1, x+1]]

for _ in range(N):
    x, y, c = input().split()
    x, y = int(x), int(y)
    if c == 'W':
        y += K
    x %= mod
    y %= mod
    for tmp in [0, K]:
        for l, r in gen_pattern((x+tmp) % mod):
            for b, t in gen_pattern((y+tmp) % mod):
                field[l][b] += 1
                field[l][t] -= 1
                field[r][b] -= 1
                field[r][t] += 1

field = np.array(field)
print((field.cumsum(axis=0).cumsum(axis=1).max()))


import itertools
import numpy as np
N, K, *XYC = open(0).read().split()
N = int(N)
K = int(K)
board = np.zeros((4 * K + 1, 4 * K + 1), dtype=np.uint16)
for x, y, c in zip(XYC[::3], XYC[1::3], XYC[2::3]):
    x = int(x)
    y = int(y)
    if c == 'W':
        x += K
    x = x % (2 * K)
    y = y % (2 * K)
    board[x, y] += 1
    board[(x + K) % (2 * K), (y + K) % (2 * K)] += 1
board[1 + 2 * K:, 1 + 2 * K:] = board[:2 * K, :2 * K]
board[1:1 + 2 * K, 1 + 2 * K:] = board[1 + 2 * K:, 1 + 2 * K:]
board[1 + 2 * K:, 1:1 + 2 * K] = board[1 + 2 * K:, 1 + 2 * K:]
board[1:1 + 2 * K, 1:1 + 2 * K] = board[1 + 2 * K:, 1 + 2 * K:]
board[0, :] = 0
board[:, 0] = 0
for j in range(1, 3 * K):
    board[:, j] += board[:, j - 1]
for j in range(1, 3 * K):
    board[j, :] += board[j - 1, :]
ans = np.max(board[K:3 * K, K:3 * K] + board[:2 * K, :2 * K] -
             board[:2 * K, K:3 * K] - board[K:3 * K, :2 * K])
print(ans)


import numpy as np
n,k=map(int,input().split())
m=np.zeros((3*k,3*k),dtype=int)
l=2*k
o=0
for _ in range(n):
  x,y,c=input().split()
  x,y=int(x)%l,int(y)%l
  t=c=='W'
  m[x,y]+=1-2*t
  o+=t
for _ in range(2):
  m[l:]=m[:k]
  m=np.cumsum(m,axis=0)
  m[:l]=m[k:]-m[:l]
  m=m.T
m=m[:l,:l]
print(o+(m+np.roll(np.roll(m,k,axis=0),k,axis=1)).max())

import numpy as np

n, k = list(map(int, input().split()))
xyc = [list(input().split()) for _ in range(n)]

b = np.zeros((3 * k - 1, 2 * k - 1), np.int64)

for x, y, c in xyc:
    x = int(x)
    y = int(y)

    q, r = divmod(x, k)
    if q % 2:
        y += k
    x = r

    if c == "W":
        y += k

    y %= 2 * k

    b[y][x] += 1

b[:k, k:] = b[k:2*k, :k-1]
b[k:2*k, k:] = b[:k, :k-1]
b[2*k:, :] = b[:k-1, :]

b = np.pad(b, (1, 0), "constant")

b = np.cumsum(b, axis=0)
b = np.cumsum(b, axis=1)

cnt = b[k:, k:] - b[k:, :-k] - b[:-k, k:] + b[:-k, :-k]
ans = cnt.max()
print(ans)


#(6,6)周期
#36種の希望

import numpy as np
N,K = list(map(int,input().split()))
KK = 2*K
hope = np.zeros((KK,KK),dtype=np.int32)

XYC = [input().split() for _ in range(N)]

for x,y,c in XYC:
  x = int(x)
  y = int(y)
  if c == 'B':
    x -= K
  x %= KK
  y %= KK
  hope[x,y] += 1
# (x,y)を希望された場合、[x,x+K), [y,y+K)に終点があるべき
# 区間の重なってる枚数を集計。1,0,0,-1, cumsum
A = np.zeros((KK+K,KK+K),dtype=np.int32)
A[:-K,:-K] = hope[:]
A[K:,:-K] += -hope[:]
A[:-K,K:] += -hope[:]
A[K:,K:] += hope[:]
A = A.cumsum(axis = 0).cumsum(axis = 1)

# 実質同じ場所をまとめる
B = A[:,:KK]
B[:,:K] += A[:,KK:] #(3K,2K)
A = B[:KK,:]
A[:K,:] += B[KK:,:] #(2K,2K)
B = A[:K,:] #(K,2K)
B[:,:K] += A[K:,K:]
B[:,K:] += A[K:,:K]

answer = B.max()
print(answer)


import sys
import numpy as np

read=sys.stdin.read
readline=sys.stdin.readline

def main():
  wb={'W':1,'B':0}
  n,k=list(map(int,readline().split()))
  xyc=[l.split() for l in read().splitlines()]
  xy=[[int(lst[0]) % (2*k),(int(lst[1])+k*wb[lst[2]]) % (2*k)] for lst in xyc]
  mat=np.zeros((k+1,2*k+1),dtype='int64')
  cand=np.zeros((k+1,k+1),dtype='int64')
  for e in xy:
    f0=e[0]>=k
    f1=e[1]>=k
    mat[e[0]-f0*k+1,e[1]+(-1)**f1*f0*k+1]+=1
  mat=np.cumsum(mat,axis=0)
  mat=np.cumsum(mat,axis=1)
  cand=mat[k,2*k]-mat[k,k:2*k+1]+mat[k,:k+1]\
       -np.reshape(mat[:k+1,2*k],(k+1,1))+2*mat[:,k:2*k+1]-2*mat[:,:k+1]
  print((max(np.max(cand),mat[k,2*k]-np.min(cand))))
  
def __starting_point():
  main()
  
  
  

__starting_point()

import sys
import numpy as np

read = sys.stdin

N, K = list(map(int, read.readline().split()))
k = 2 * K
xyc = np.array(read.read().split(), np.str)
x = xyc[::3].astype(int)
y = xyc[1::3].astype(int)
c = xyc[2::3]

x[c == 'B'] -= K
x %= k
y %= k

grid = np.zeros((3 * K, 3 * K), np.int64)
np.add.at(grid, (x, y), 1)
np.add.at(grid, (x + K, y + K), 1)
np.subtract.at(grid, (x + K, y), 1)
np.subtract.at(grid, (x, y + K), 1)
np.cumsum(grid, axis=0, out=grid)
np.cumsum(grid, axis=1, out=grid)

p1 = grid[:K, :K] + grid[k:, k:] + grid[K:k, K:k] + grid[k:, :K] + grid[:K, k:]
p2 = grid[K:k, :K] + grid[K:k, k:] + grid[:K, K:k] + grid[k:, K:k]
print((max(p1.max(), p2.max())))


ri = lambda: int(input())
rl = lambda: list(map(int,input().split()))
rr = lambda N: [ri() for _ in range(N)]
YN = lambda b: print('YES') if b else print('NO')
INF = 10**18
 
N,K=rl()
 
W = [[0 for _ in range(K+3)] for _ in range(K+3)]
for i in range(N):
    x,y,c=input().split()
    x = int(x)%(2*K)
    y = (int(y) if c=='W' else int(y)+K)%(2*K)
    if (x<K)^(y<K):
        x %= K
        y %= K
        W[0][y+1] += 1
        W[x+1][y+1] -= 2
        W[0][K+1] -= 1
        W[x+1][K+1] += 1
        W[x+1][0] += 1
        W[K+1][0] -= 1
        W[K+1][y+1] += 1
    else:
        x %= K
        y %= K
        W[0][0] += 1
        W[x+1][0] -= 1
        W[0][y+1] -= 1
        W[x+1][y+1] += 2
        W[K+1][y+1] -= 1
        W[x+1][K+1] -= 1
        W[K+1][K+1] += 1
 
for x in range(0,K+2):
    for y in range(0,K+2):
        W[x][y] += W[x][y-1]
for y in range(0,K+2):
    for x in range(0,K+2):
        W[x][y] += W[x-1][y]
 
ans = 0
for x in range(K+1):
    for y in range(K+1):
        res = W[x][y]
        ans = max(ans,res,N-res)
 
print(ans)

import itertools
import numpy as np
N, K, *XYC = open(0).read().split()
N = int(N)
K = int(K)
board = np.zeros((4 * K + 1, 4 * K + 1), dtype=np.uint16)
for x, y, c in zip(XYC[::3], XYC[1::3], XYC[2::3]):
    x = int(x)
    y = int(y)
    if c == 'W':
        x += K
    x = x % (2 * K)
    y = y % (2 * K)
    board[x, y] += 1
    board[(x + K) % (2 * K), (y + K) % (2 * K)] += 1
board[1 + 2 * K:, 1 + 2 * K:] = board[:2 * K, :2 * K]
board[1:1 + 2 * K, 1 + 2 * K:] = board[1 + 2 * K:, 1 + 2 * K:]
board[1 + 2 * K:, 1:1 + 2 * K] = board[1 + 2 * K:, 1 + 2 * K:]
board[1:1 + 2 * K, 1:1 + 2 * K] = board[1 + 2 * K:, 1 + 2 * K:]
board[0, :] = 0
board[:, 0] = 0
for j in range(1, 1 + 4 * K):
    board[:, j] += board[:, j - 1]
for j in range(1, 1 + 4 * K):
    board[j, :] += board[j - 1, :]
ans = np.max(board[K:3 * K, K:3 * K] + board[:2 * K, :2 * K] -
             board[:2 * K, K:3 * K] - board[K:3 * K, :2 * K])
print(ans)


import numpy as np
n, k = map(int, input().split())
list_subj = []
for i in range(n):
  x, y, c = input().split()
  if c == "W":
    list_subj.append([int(x) % (2*k), int(y) % (2*k)])
  else:
    list_subj.append([(int(x) + k) % (2*k), int(y) % (2*k)])

imos_field = [[0] * (2*k+1) for _ in range(2*k+1)]
for x, y in list_subj:
  for place in (0, k):
    adj_y = (y + place) % (2 * k)
    if adj_y >= k - 1:
      imos_y = [(adj_y-k+1, adj_y+1)]
    else:
      imos_y = [(0, adj_y+1), (adj_y+k+1, 2*k)]
    adj_x = (x + place) % (2 * k)
    if adj_x >= k - 1:
      imos_x = [(adj_x-k+1, adj_x+1)]
    else:
      imos_x = [(0, adj_x+1), (adj_x+k+1, 2*k)]
    for bottom, top in imos_y:
      for left, right in imos_x:
        imos_field[bottom][left] += 1
        imos_field[top][left] -= 1
        imos_field[bottom][right] -= 1
        imos_field[top][right] += 1

result = np.cumsum(imos_field, axis=1)
result = np.cumsum(result, axis=0)
result = int(np.max(result))
print(result)

import sys
import numpy as np
from collections import Counter

read = sys.stdin

N, K = list(map(int, read.readline().split()))
k = 2 * K
xyc = np.array(read.read().split(), np.str).reshape(-1, 3)
x = xyc[:, 0].astype(int)
y = xyc[:, 1].astype(int)
c = xyc[:, 2]

x[c == 'B'] -= K
x %= k
y %= k

grid = np.zeros((3 * K, 3 * K), np.int64)
np.add.at(grid, (x, y), 1)
np.add.at(grid, (x + K, y + K), 1)
np.subtract.at(grid, (x + K, y), 1)
np.subtract.at(grid, (x, y + K), 1)
np.cumsum(grid, axis=0, out=grid)
np.cumsum(grid, axis=1, out=grid)

p1 = grid[:K, :K] + grid[k:, k:] + grid[K:k, K:k] + grid[k:, :K] + grid[:K, k:]
p2 = grid[K:k, :K] + grid[K:k, k:] + grid[:K, K:k] + grid[k:, K:k]
print((max(p1.max(), p2.max())))


import numpy as np

N, K = map(int, input().split())
_3K = 3 * K
_2K = 2 * K
G = np.zeros((_2K, _3K), dtype='int64') # 後から 2K * K に圧縮する
for _ in range(N):
    x, y, c = input().split()
    x, y = int(x), int(y)
    # 2K * 2K の黒の希望に置き換え
    if c == 'B':
        x = x % _2K
        y = y % _2K
    else:
        x = (x + K) % _2K
        y = y % _2K
    # さらに、 2K * K の黒の希望に圧縮する
    if (y >= K) and (x >= K):
        x -= K
        y -= K
    if (y >= K) and (x < K):
        x += K
        y -= K
    # 塗り方は右下がどのマスに来るかの 2K * K 通り
    # → 最終的に 2K * K のグリッドで表すことができる
    # 各希望を満たす塗り方は K * K 通り
    # → 2K * K のグリッド内の希望を満たす K * K マスに 1 を加算すれば、
    #   全希望の加算後には各マス＝各塗り方がいくつの希望を満たすかがわかる
    # K * K マスに 1 を加算するには o(K^2) かかってしまう
    # → いもす法を使う
    # 塗り方を 3K * 2K の範囲で考えて累積和をとった後、 2K * K の範囲に圧縮する
    G[y, x] += 1
    G[y+K, x+K] += 1
    G[y+K, x] -= 1
    G[y, x+K] -= 1

# 3K * 2K の範囲の累積和をとる
G = G.cumsum(axis=1).cumsum(axis=0)
# 2K * K の範囲に圧縮
G = G[:K, :_2K] + G[K:_2K, K:_3K] + np.concatenate((G[:K, _2K:_3K], G[K:_2K, :K]), axis=1)
ans = G.max()
print(ans)

def d_checker():
    # 参考1: https://pitsbuffersolution.com/compro/atcoder/arc089d.php
    # 参考2: https://atcoder.jp/contests/abc086/submissions/3271380
    import numpy as np
    N, K = [int(i) for i in input().split()]

    def get_bound(p):
        """ある希望を満たすような角のマスの集合はKxK正方形区間のようになっている
        p<K-1 のときはその正方形を分割しないとならない"""
        return [(0, p + 1), (p + K + 1, 2 * K)] if p < K - 1 else [(p - K + 1, p + 1)]

    # マス(x, y)が白⇔マス(x, y+K)が黒なので、希望の色を黒に統一する
    # 市松模様の周期は2Kなので、x, y座標をそれぞれ2Kで剰余を取った座標と同一視できる
    requests_black = [[0] * (2 * K + 1) for _ in range(2 * K + 1)]
    for _ in range(N):
        x, y, c = input().split()
        x = int(x) % (2 * K)
        y = int(y) % (2 * K) if c == 'B' else (int(y) + K) % (2 * K)

        for shift in (0, K):  # 2Kx2Kの市松模様の中に同色の領域が2つずつあることを反映
            # bottom, top, left, right
            for b, t in get_bound((y + shift) % (2 * K)):
                for l, r in get_bound((x + shift) % (2 * K)):
                    # 2次元imos法(左上、左下、右上、右下に±1することと対応)
                    requests_black[b][l] += 1
                    requests_black[t][l] -= 1
                    requests_black[b][r] -= 1
                    requests_black[t][r] += 1
    # 最後に累積和を取ると、あるマスを正方形の角としたとき叶えられる希望の数がわかる
    return int(np.max(np.cumsum(np.cumsum(requests_black, axis=1), axis=0)))

print(d_checker())

#!/usr/bin/env python3

def main():
    na = list(map(int, input().split()))
    N = na[0]
    K = na[1]
    x = []
    y = []
    c = []
    for i in range(N):
        sa = input().split()
        x.append(int(sa[0]))
        y.append(int(sa[1]))
        c.append(True if sa[2] == 'W' else False)

    hopes = [[0 for j in range(K)] for i in range(K)]
    ysum = [[0 for j in range(K * 2)] for i in range(K)]

    score = 0
    for i in range(N):
        xmod = x[i] % K
        ymod = y[i] % K
        f = (int(x[i] / K) + int(y[i] / K)) % 2 == 1
        c[i] ^= f
        if c[i]:
            score += 1
        h = -1 if c[i] else 1
        hopes[xmod][ymod] += h

    for i in range(K):
        s = 0
        for j in range(K):
            s += hopes[i][j]
            ysum[i][j] = s
        for j in range(K):
            s -= hopes[i][j]
            ysum[i][K + j] = s

    smax = 0
    for j in range(K):
        s = 0
        for i in range(K):
            s += ysum[i][K + j]
        for i in range(K):
            s += (ysum[i][j] - ysum[i][K + j])
            smax = max(smax, s)
        for i in range(K):
            s -= (ysum[i][j] - ysum[i][K + j])
            smax = max(smax, s)

    print((score + smax))


def __starting_point():
    main()


__starting_point()

N, K = (int(i) for i in input().split())
W = list()
for index in range(N):
	x, y, c = (s for s in input().split())
	x = int(x)
	y = int(y)
	c = 0 if c == "W" else 1
	if x%(2*K) != x%K:
		c = 1-c
	if y%(2*K) != y%K:
		c = 1-c
	W.append((x%K, y%K, c))

w = [[0 for _ in range(K)] for _ in range(K)]
b = [[0 for _ in range(K)] for _ in range(K)]
wx = [0 for _ in range(K)]
wy = [0 for _ in range(K)]
bx = [0 for _ in range(K)]
by = [0 for _ in range(K)]
for x, y, c in W:
	if c == 0:
		w[x][y] += 1
		wx[x] += 1
		wy[y] += 1
	else:
		b[x][y] += 1
		bx[x] += 1
		by[y] += 1

M = 0
for row in w:
	M += sum(row)

s = M
for x in range(K):
	tmp = s
	for y in range(K):
		s += by[y]
		s -= wy[y]
		M = max(s, N-s, M)
	for y in range(K):
		by[y] += w[x][y]
		by[y] -= b[x][y]
		wy[y] += b[x][y]
		wy[y] -= w[x][y]
	tmp += bx[x]
	tmp -= wx[x]
	s = tmp
	M = max(s, N-s, M)

print(M)

import numpy as np


def solve(string):
    n, k, *xyc = string.split()
    k = int(k)
    l = 2 * int(k)
    xy = [(int(x) % l, int(y) % l) if c == "W" else (int(x) % l, (int(y) + k) % l)
          for x, y, c in zip(xyc[::3], xyc[1::3], xyc[2::3])]
    ans = [[0 for j in range(l + 0)] for i in range(l + 0)]
    for _x, _y in xy:
        if (_x - k + 0.5) * (_y - k + 0.5) > 0:
            lt = 2
            lte = 1
            ans[0][0] += 1
        else:
            lt = -2
            lte = -1
        _x %= k
        _y %= k
        ans[_x][_y] += lt
        ans[_x + k][_y] -= lt
        ans[_x][_y + k] -= lt
        ans[_x + k][_y + k] += lt
        ans[_x + k][0] += lte
        ans[0][_y + k] += lte
        ans[_x][0] -= lte
        ans[0][_y] -= lte
    return str(np.asarray(ans).cumsum(axis=1).cumsum(axis=0).max())


def __starting_point():
    n, m = list(map(int, input().split()))
    print((solve('{} {}\n'.format(n, m) + '\n'.join([input() for _ in range(n)]))))

__starting_point()

import sys
input = sys.stdin.readline

n,k = map(int, input().split())
grid = [[0]*k for i in range(k)]
black = 0
for i in range(n):
    a,b,c =input().split()
    a,b = int(a), int(b)
    f = a//k + b//k
    a %= k
    b %= k
    if (c == "W" and f%2==0) or (c == "B" and f%2==1):
        grid[a][b] += 1
    else:
        grid[a][b] -= 1
        black += 1

s = [[0]*(k+1) for i in range(k+1)]
for i in range(k):
    for j in range(k):
        s[i+1][j+1] = s[i][j+1] + s[i+1][j] - s[i][j] + grid[i][j]

ans = 0
for i in range(k):
    for j in range(k):
        a = s[k][k] - s[i][k] - s[k][j] + 2*s[i][j] + black
        ans = max(ans, max(a, n-a))
print(ans)

import numpy as np
n, k = list(map(int, input().split()))

def get_bound(x):
    if x < k-1:
        return [(0, x+1), (x+k+1, 2*k)]
    else:
        return [(x-k+1, x+1)]

blacks = [[0]*(2*k+1) for _ in range(2*k+1)]
for _ in range(n):
    x, y, c = input().split()
    x = int(x)%(2*k)
    y = int(y)%(2*k) if c == 'B' else (int(y)+k)%(2*k)

    for shift in [0, k]:
        for b, t in get_bound((y+shift)%(2*k)):
            for l, r in get_bound((x+shift)%(2*k)):
                blacks[b][l] += 1
                blacks[t][l] -= 1
                blacks[b][r] -= 1
                blacks[t][r] += 1
        
ans = np.max(np.cumsum(np.cumsum(blacks, axis = 1), axis = 0))
print((int(ans)))


import numpy as np
import sys

def sum2d(i1,j1,i2,j2):
    A[i1][j1] += 1
    A[i1][j2] -= 1
    A[i2][j1] -= 1
    A[i2][j2] += 1

N,K = list(map(int,input().split()))
XYC = [list(input().split()) for _ in range(N)]

A = [[0 for _ in range(K*2+1)] for _ in range(K*2+1)]

for x,y,c in XYC:
    i = (int(x) if c=="W" else int(x)+K) % (K*2)
    j = int(y) % (K*2)
    i0 = i%K
    j0 = j%K
    if (i<K and j<K) or (i>=K and j>=K):
        sum2d(0,0,i0,j0) # 左上
        sum2d(i0+K,0,K*2,j0) # 右上
        sum2d(i0,j0,i0+K,j0+K) # 真ん中
        sum2d(0,j0+K,i0,K*2) # 左下
        sum2d(i0+K,j0+K,K*2,K*2) # 右下
    else:
        sum2d(i0,0,i0+K,j0) # 上
        sum2d(0,j0,i0,j0+K) # 左
        sum2d(i0+K,j0,K*2,j0+K) # 右
        sum2d(i0,j0+K,i0+K,K*2) # 下

# 2次元累積和
AA = np.array(A)
for i in range(K*2):
    AA[i+1, :] += AA[i, :]
for j in range(K*2):
    AA[:, j+1] += AA[:, j]

print((AA.max()))




import numpy as np

n, k = list(map(int, input().split()))
xyc = [list(input().split()) for _ in range(n)]

b = np.zeros((2 * k, k), np.int32)

for x, y, c in xyc:
    x = int(x)
    y = int(y)

    q, r = divmod(x, k)
    if q % 2:
        y += k
    x = r

    if c == "W":
        y += k

    y %= 2 * k

    b[y][x] += 1

b = np.vstack([b, b])
b = np.hstack([b, np.roll(b, k, axis=0)])

b = np.pad(b, (1, 0), "constant")
b = np.cumsum(b, axis=0)
b = np.cumsum(b, axis=1)

cnt = b[k:, k:] - b[k:, :-k] - b[:-k, k:] + b[:-k, :-k]
ans = cnt.max()
print(ans)


import numpy as np

N, K = map(int, input().split())
K2 = K*2

M = np.zeros((K2, K2), int)
nb = 0
for _ in range(N):
  x, y, c = input().split()
  x = int(x) % K2
  y = int(y) % K2
  if c=='B': nb+=1
  M[x, y] += 1 if c=='W' else -1

Sx = np.zeros((K2, K2+1), int)
for y in range(K2):
  Sx[:, y+1] = Sx[:, y] + M[:, y]

S = np.zeros((K2+1, K2+1), int)
for x in range(K2):
  S[x+1] = S[x] + Sx[x]

ans = -1000000
for x in range(K2):
  x0 = 0
  x1 = max(x-K , 0)
  x2 = x
  x3 = min(x+K , K2)
  x4 = K2

  T1 = S[x4] - S[x3] + S[x2] - S[x1]
  T2 = S[x3] - S[x2] + S[x1] - S[x0]

  U = T1[K2] - T1[K:K2] + T1[:K] + T2[K:K2] - T2[:K]
  ans = max(ans, np.max(U))
  
print(nb + ans)

import numpy as np
import sys

N, K = map(int, input().split())
K2 = K * 2
Mij = [[0 for _ in range(K2 + 1)] for _ in range(K2 + 1)]

def imos(i1, j1, i2, j2):
    Mij[i1][j1] += 1
    Mij[i1][j2] -= 1
    Mij[i2][j1] -= 1
    Mij[i2][j2] += 1

for _ in range(N):
    i, j, s = sys.stdin.readline().split()
    i = int(i) % K2
    j = int(j) % K2
    if s == "B":
        i = (i + K) % K2
    i1 = i % K
    j1 = j % K
    if (i < K and j < K) or (K <= i and K <= j):
        imos(0, 0, i1, j1)
        imos(0, j1 + K, i1, K2)
        imos(i1 + K, 0, K2, j1)
        imos(i1 + K, j1 + K, K2, K2)
        imos(i1, j1, i1 + K, j1 + K)
    else:
        imos(0, j1, i1, j1 + K)
        imos(i1 + K, j1, K2, j1 + K)
        imos(i1, 0, i1 + K, j1)
        imos(i1, j1 + K, i1 + K, K2)

# 累積和
Mij = np.array(Mij)
for x in range(K2):
    Mij[:, x + 1] += Mij[:, x]
for y in range(K2):
    Mij[y + 1, :] += Mij[y, :]
print(Mij.max())

import numpy as np

def main():
    n, k = map(int, input().split())
    p = [list(map(str, input().split())) for _ in range(n)]
    arr = [[[0]*2 for j in range(k)] for i in range(k)]
    for i in range(n):
        x, y, c = p[i]
        x, y = int(x), int(y)
        mx, my = x%k, y%k
        f = False
        if (x//k)%2 != (y//k)%2:
            f = not f
        if c == "W":
            f = not f
        if f:
            arr[0][0][0] += 1
            arr[mx][0][0] -= 1
            arr[0][my][0] -= 1
            arr[mx][my][0] += 2
        else:
            arr[0][my][0] += 1
            arr[mx][0][0] += 1
            arr[mx][my][0] -= 2
        f = False
        if (x//k)%2 != (y//k)%2:
            f = not f
        if c == "B":
            f = not f
        if f:
            arr[0][0][1] += 1
            arr[mx][0][1] -= 1
            arr[0][my][1] -= 1
            arr[mx][my][1] += 2
        else:
            arr[0][my][1] += 1
            arr[mx][0][1] += 1
            arr[mx][my][1] -= 2
    np_arr = np.array(arr)
    np_arr = np.cumsum(np_arr, axis=0)
    np_arr = np.cumsum(np_arr, axis=1)
    print(int(np.max(np_arr)))

def __starting_point():
    main()
__starting_point()

import numpy as np
# from time import time

# t0 = time()
N, K = list(map(int, input().split()))
B = np.zeros((2 * K, 2 * K), np.int32)
W = np.zeros((2 * K, 2 * K), np.int32)
# t1 = time()
# print(t1 - t0)
for _ in range(N):
    x, y, c = input().split()
    if c == "B":
        B[int(x) % (2 * K)][int(y) % (2 * K)] += 1
    else:
        W[int(x) % (2 * K)][int(y) % (2 * K)] += 1
# t2 = time()
# print(t2 - t1)
SB = np.zeros((4 * K + 1, 4 * K + 1), np.int32)
SW = np.zeros((4 * K + 1, 4 * K + 1), np.int32)
# t3 = time()
# print(t3 - t2)
SB[0*K+1:2*K+1, 0*K+1:2*K+1] = B
SB[0*K+1:2*K+1, 2*K+1:4*K+1] = B
SB[2*K+1:4*K+1, 0*K+1:2*K+1] = B
SB[2*K+1:4*K+1, 2*K+1:4*K+1] = B
SW[0*K+1:2*K+1, 0*K+1:2*K+1] = W
SW[0*K+1:2*K+1, 2*K+1:4*K+1] = W
SW[2*K+1:4*K+1, 0*K+1:2*K+1] = W
SW[2*K+1:4*K+1, 2*K+1:4*K+1] = W
# t4 = time()
# print(t4 - t3)
np.cumsum(SB, 0, out=SB)
np.cumsum(SB, 1, out=SB)
np.cumsum(SW, 0, out=SW)
np.cumsum(SW, 1, out=SW)
# t5 = time()
# print(t5 - t4)
ans = 0
cand = SB[1*K:3*K+1, 1*K:3*K+1].copy()
cand -= SB[0*K:2*K+1, 1*K:3*K+1]
cand -= SB[1*K:3*K+1, 0*K:2*K+1]
cand += SB[0*K:2*K+1, 0*K:2*K+1]
cand += SB[2*K:4*K+1, 2*K:4*K+1]
cand -= SB[1*K:3*K+1, 2*K:4*K+1]
cand -= SB[2*K:4*K+1, 1*K:3*K+1]
cand += SB[1*K:3*K+1, 1*K:3*K+1]
cand += SW[2*K:4*K+1, 1*K:3*K+1]
cand -= SW[1*K:3*K+1, 1*K:3*K+1]
cand -= SW[2*K:4*K+1, 0*K:2*K+1]
cand += SW[1*K:3*K+1, 0*K:2*K+1]
cand += SW[1*K:3*K+1, 2*K:4*K+1]
cand -= SW[0*K:2*K+1, 2*K:4*K+1]
cand -= SW[1*K:3*K+1, 1*K:3*K+1]
cand += SW[0*K:2*K+1, 1*K:3*K+1]
ans = np.max(cand)
# t6 = time()
# print(t6 - t5)

print(ans)


import numpy as np
N, K = map(int, input().split())
mod = 2*K
field = [[0]*(2*K+1) for _ in range(2*K+1)]

def gen_pattern(x):
    if x < K-1:
        return [[0, x+1], [x+K+1, 2*K]]
    else:
        return [[x-K+1, x+1]]

for _ in range(N):
    x, y, c = input().split()
    x, y = int(x), int(y)
    if c == 'W':
        y += K
    x %= mod
    y %= mod
    for tmp in [0, K]:
        for l, r in gen_pattern((x+tmp) % mod):
            for b, t in gen_pattern((y+tmp) % mod):
                field[l][b] += 1
                field[l][t] -= 1
                field[r][b] -= 1
                field[r][t] += 1
print(np.max(np.cumsum(np.cumsum(field, axis=0), axis=1)))

#(6,6)周期
#36種の希望

import numpy as np
N,K = list(map(int,input().split()))
KK = 2*K
hope = np.zeros((KK,KK),dtype=np.int32)

for _ in range(N):
  x,y,c  = input().split()
  x = int(x)
  y = int(y)
  if c == 'B':
    x -= K
  hope[x%KK,y%KK] += 1
# (x,y)を希望された場合、[x,x+K), [y,y+K)に終点があるべき
# 区間の重なってる枚数を集計。1,0,0,-1, cumsum
A = np.zeros((KK+K,KK+K),dtype=np.int32)
A[:-K,:-K] = hope[:]
A[K:,:-K] += -hope[:]
A[:-K,K:] += -hope[:]
A[K:,K:] += hope[:]
A = A.cumsum(axis = 0).cumsum(axis = 1)

# 実質同じ場所をまとめる
B = A[:,:KK]
B[:,:K] += A[:,KK:] #(3K,2K)
A = B[:KK,:]
A[:K,:] += B[KK:,:] #(2K,2K)
B = A[:K,:] #(K,2K)
B[:,:K] += A[K:,K:]
B[:,K:] += A[K:,:K]

answer = B.max()
print(answer)


import numpy as np


def imos2d(x1, y1, x2, y2, board):
    board[y1][x1] += 1
    board[y2][x2] += 1
    board[y2][x1] -= 1
    board[y1][x2] -= 1


def __starting_point():
    N, K = list(map(int, input().split()))
    lines = [input() for _ in range(N)]

    # N, K = 4, 3
    # lines = ["0 1 W", "1 2 W", "5 3 B", "5 4 B"]

    K2 = 2 * K
    add_dict = {"W": 0, "B": K}
    board = [[0 for _ in range(K2 + 1)] for _ in range(K2 + 1)]
    for line in lines:
        ls = line.split()
        x = int(ls[0]) % K2
        y = (int(ls[1]) + add_dict[ls[2]]) % K2
        x_ = x % K
        y_ = y % K

        # 左上・右上・中央・左下・右下
        if (x < K and y < K) or (K <= x and K <= y):
            # 左上
            imos2d(0, 0, x_ + 1, y_ + 1, board)
            # 右上
            imos2d(x_ + K + 1, 0, K2, y_ + 1, board)
            # 左下
            imos2d(0, y_ + K + 1, x_ + 1, K2, board)
            # 右下
            imos2d(x_ + K + 1, y_ + K + 1, K2, K2, board)
            # 中央
            imos2d(x_ + 1, y_ + 1, x_ + K + 1, y_ + K + 1, board)
        # 上・下・左・右
        else:
            # 上
            imos2d(x_ + 1, 0, x_ + K + 1, y_ + 1, board)
            # 下
            imos2d(x_ + 1, y_ + K + 1, x_ + K + 1, K2, board)

            # 左
            imos2d(0, y_ + 1, x_ + 1, y_ + K + 1, board)
            imos2d(x_ + K + 1, y_ + 1, K2, y_ + K + 1, board)

    board = np.array(board)
    for x in range(K2):
        board[:, x + 1] += board[:, x]
    for y in range(K2):
        board[y + 1, :] += board[y, :]

    print((board.max()))

__starting_point()

import sys
import numpy as np
from collections import Counter

read = sys.stdin

N, K = list(map(int, read.readline().split()))
k = 2 * K
xyc = np.array(read.read().split(), np.str).reshape(-1, 3)
x = xyc[:, 0].astype(int)
y = xyc[:, 1].astype(int)
c = xyc[:, 2]

x[c == 'B'] -= K
x %= k
y %= k

'''
# grid[[1,1],[2,2]]+=1 としてもgrid[1,2]=1であり重複は考慮されない。
# uniqueを使って(x,y)の重複をカウントする
# return_countはver1.9からだった・・・ ダメじゃん
xy, cnt = np.unique(x + y * 10000, return_counts=True)
x = xy % 10000
y = xy // 10000
'''
xy = Counter(list(zip(x.tolist(), y.tolist())))
cnt = np.array(list(xy.values()), np.int64)
xy = np.array(list(xy.keys()), np.int64)
x = xy[:, 0]
y = xy[:, 1]

grid = np.zeros((3 * K, 3 * K), np.int64)
grid[x, y] += cnt
grid[x + K, y + K] += cnt
grid[x + K, y] -= cnt
grid[x, y + K] -= cnt
np.cumsum(grid, axis=0, out=grid)
np.cumsum(grid, axis=1, out=grid)

p1 = grid[:K, :K] + grid[k:, k:] + grid[K:k, K:k] + grid[k:, :K] + grid[:K, k:]
p2 = grid[K:k, :K] + grid[K:k, k:] + grid[:K, K:k] + grid[k:, K:k]
print((max(p1.max(), p2.max())))


import numpy as np


def imos2d(x1, y1, x2, y2, board):
    board[y1][x1] += 1
    board[y2][x2] += 1
    board[y2][x1] -= 1
    board[y1][x2] -= 1


def __starting_point():
    N, K = list(map(int, input().split()))
    lines = [input() for _ in range(N)]

    K2 = 2 * K
    add_dict = {"W": 0, "B": K}
    board = [[0 for _ in range(K2 + 1)] for _ in range(K2 + 1)]
    for line in lines:
        ls = line.split()
        x = int(ls[0]) % K2
        y = (int(ls[1]) + add_dict[ls[2]]) % K2
        x_ = x % K
        y_ = y % K

        # 左上・右上・中央・左下・右下
        if (x < K and y < K) or (K <= x and K <= y):
            # 左上
            imos2d(0, 0, x_ + 1, y_ + 1, board)
            # 右上
            imos2d(x_ + K + 1, 0, K2, y_ + 1, board)
            # 左下
            imos2d(0, y_ + K + 1, x_ + 1, K2, board)
            # 右下
            imos2d(x_ + K + 1, y_ + K + 1, K2, K2, board)
            # 中央
            imos2d(x_ + 1, y_ + 1, x_ + K + 1, y_ + K + 1, board)
        # 上・下・左・右
        else:
            # 上
            imos2d(x_ + 1, 0, x_ + K + 1, y_ + 1, board)
            # 下
            imos2d(x_ + 1, y_ + K + 1, x_ + K + 1, K2, board)

            # 左
            imos2d(0, y_ + 1, x_ + 1, y_ + K + 1, board)
            imos2d(x_ + K + 1, y_ + 1, K2, y_ + K + 1, board)

    board = np.array(board)
    for x in range(K2):
        board[:, x + 1] += board[:, x]
    for y in range(K2):
        board[y + 1, :] += board[y, :]

    print((board.max()))

__starting_point()

N, K = map(int, input().split())

score = [[0] * (K+1) for y in range(K+1)]
base_hope = 0

for i in range(N):
    x, y, c = input().split()
    x2, y2 = int(x) // K, int(y) // K
    x_coord, y_coord = int(x) % K + 1, int(y) % K + 1
    if ((x2 + y2) % 2 == 0 and c == "W") or ((x2 + y2) % 2 == 1 and c == "B"):
        score[y_coord][x_coord] += 1
        base_hope += 1
    else:
        score[y_coord][x_coord] -= 1

xy = [(x, y) for x in range(K) for y in range(K)]
for x, y in xy:
    score[y+1][x+1] += score[y+1][x] + score[y][x+1] - score[y][x]

max_hope = 0
for x, y in xy:
    hope = base_hope - score[K][x] - score[y][K] + 2 * score[y][x]
    true_hope = hope if hope > N - hope else N - hope
    if true_hope > max_hope:
        max_hope = true_hope

print(max_hope)

def main():
  n, k = map(int, input().split())
  mp1 = [[0] * k for _ in range(k)]
  mp2 = [[0] * k for _ in range(k)]
  for _ in range(n):
    x, y, c = input().split()
    t = int(x) // k + int(y) // k
    x = int(x) % k
    y = int(y) % k
    if c == "B":
      t += 1
    if t % 2:
      mp1[y][x] += 1
    else:
      mp2[y][x] += 1
  
  mp10 = mp1[0]
  mp20 = mp2[0]
  for x in range(1, k):
    mp10[x] += mp10[x - 1]
    mp20[x] += mp20[x - 1]
  
  for y in range(1, k):
    acc1 = 0
    acc2 = 0
    mp1y = mp1[y]
    mp2y = mp2[y]
    mp1y1 = mp1[y - 1]
    mp2y1 = mp2[y - 1]
    for x in range(k):
      acc1 += mp1y[x]
      mp1y[x] = acc1 + mp1y1[x]
      acc2 += mp2y[x]
      mp2y[x] = acc2 + mp2y1[x]
  
  ans = 0
  sum1 = mp1[k - 1][k - 1]
  sum2 = mp2[k - 1][k - 1]
  mp1k = mp1[k - 1]
  mp2k = mp2[k - 1]
  for y in range(k):
    mp1y = mp1[y]
    mp1yk = mp1y[k - 1]
    mp2y = mp2[y]
    mp2yk = mp2y[k - 1]
    for x in range(k):
      mp1yx = mp1y[x]
      mp2yx = mp2y[x]
      mp1kx = mp1k[x]
      mp2kx = mp2k[x]
  
      a1 = 2 * mp1yx + sum1 - mp1yk - mp1kx + mp2kx + mp2yk - 2 * mp2yx
      a2 = 2 * mp2yx + sum2 - mp2yk - mp2kx + mp1kx + mp1yk - 2 * mp1yx
  
      if ans < a1:
        ans = a1
      if ans < a2:
        ans = a2
  
  
  print(ans)

main()

# coding: utf-8
import sys
import numpy as np

sr = lambda: sys.stdin.readline().rstrip()
ir = lambda: int(sr())
lr = lambda: list(map(int, sr().split()))

# 縦K、横2*Kの長方形に全ての希望をWとして入れる
# numpyの累積和、最後にmaxをとる
N, K = lr()
table = [[0] * 2*K for _ in range(K)]
for _ in range(N):
    x, y, c = sr().split()
    x = int(x); y = int(y)
    if c == 'B':
        x -= K  # ここで全てWとして扱える
    x %= 2 * K; y %= 2 * K
    if x >= K and y >= K:
        x -= K; y -= K
    elif y >= K:
        x += K; y -= K
    # 長方形に入った
    table[y][x] += 1

table = np.array(table, dtype=np.int32)
table = np.concatenate([table, table], axis=1)
table2 = np.roll(table, K, axis=1)
table = np.concatenate([table, table2], axis=0)
table_cum = table.cumsum(axis=1).cumsum(axis=0)
prev = table_cum.copy()
table_cum[:, K:] -= prev[:, :-K]
table_cum[K:, :] -= prev[:-K, :]
table_cum[K:, K:] += prev[:-K, :-K]
answer = table_cum.max()
print(answer)


from numpy import *
N,K = map(int,input().split())
M = zeros((3*K,3*K),int)
L = 2*K
O = 0

for n in range(N):
  x,y,c = input().split()
  x = int(x)%L
  y = int(y)%L
  t = c=="W"
  M[x,y]+=1-2*t
  O+=t

for n in range(2):
  M[L:] = M[:K]
  M = cumsum(M,axis=0)
  M[:L] = M[K:]-M[:L]
  M = M.T
  
M = M[:L,:L]
print(O+(M+roll(roll(M,K,axis=0),K,axis=1)).max())