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 C++14 (GCC 5.4.1) (judge verdict: Accepted)

#include <bits/stdc++.h>

using namespace std;

#define countof(a) (sizeof(a)/sizeof(*a))

#define vi vector<int>
#define vvi vector<vector<int> >
#define vpi vector<pi >
#define pi pair<int,int>
#define fi first
#define se second
#define all(n) n.begin(), n.end()

#define FROMTO(var, from, to) for (register int var = (from), var##down = ((int)(to)) < ((int)(from));var##down ? (var >= (int)(to)) : (var <= (int)(to));var##down ? var-- : var++)
#define UPTO(var, from, to)   for (register int var = (from); var <= ((int)to); var++)
#define DOWNTO(var, from, to) for (register int var = (from); var >= ((int)to); var--)
#define FOR(var, to)          UPTO(var, 0, (to)-1)
#define DOWN(var, from)       DOWNTO(var, (from)-1, 0) 

#define INIT(var, val) FOR(i,countof(var)) var[i] = val
#define INPUT(var) FOR(i,countof(var)) cin >> var[i]
#define INPUT1(var) FOR(i,countof(var)) cin >> var[i], var[i]--

#define SORT(v) qsort(v,countof(v),sizeof(*v),int_less)
#define SORTT(v) qsort(v,countof(v),sizeof(*v),int_greater)
#define QSORT(v,b) qsort(v,countof(v),sizeof(*v),b)

#define MOD 1000000007
#define INF ((1 << 30)-1)
#define LINF ((1LL << 62)-1)

typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int8_t s8;
typedef int16_t s16;
typedef int32_t s32;
typedef int64_t s64;

/* ------------------------ */
/* BEGIN EXTERNAL LIBRARIES */
/* ------------------------ */

template<int mod>
struct ModInt{
    int x;
    ModInt():x(0){}
    ModInt(long long y):x(y>=0?y%mod:(mod-(-y)%mod)%mod){}
    ModInt &operator+=(const ModInt &p){
        if((x+=p.x)>=mod)x-=mod;
        return *this;
    }
    ModInt &operator-=(const ModInt &p){
        if((x+=mod-p.x)>=mod)x-=mod;
        return *this;
    }
    ModInt &operator*=(const ModInt &p){
        x=(int)(1LL*x*p.x%mod);
        return *this;
    }
    ModInt &operator/=(const ModInt &p){
        *this*=p.inverse();
        return *this;
    }
    ModInt operator-()const{return ModInt(-x);}
    ModInt operator+(const ModInt &p)const{return ModInt(*this)+=p;}
    ModInt operator-(const ModInt &p)const{return ModInt(*this)-=p;}
    ModInt operator*(const ModInt &p)const{return ModInt(*this)*=p;}
    ModInt operator/(const ModInt &p)const{return ModInt(*this)/=p;}
    bool operator==(const ModInt &p)const{return x==p.x;}
    bool operator!=(const ModInt &p)const{return x!=p.x;}
    operator int() const { return x; }                           // added by QCFium
    ModInt operator=(const int p) {x = p; return ModInt(*this);} // added by QCFium
    ModInt inverse()const{
        int a=x,b=mod,u=1,v=0,t;
        while(b>0){
            t=a/b;
            a-=t*b;
            swap(a,b);
            u-=t*v;
            swap(u,v);
        }
        return ModInt(u);
    }
    friend ostream &operator<<(ostream &os,const ModInt<mod> &p){
        return os<<p.x;
    }
    friend istream &operator>>(istream &is,ModInt<mod> &a){
        long long x;
        is>>x;
        a=ModInt<mod>(x);
        return (is);
    }
};
typedef ModInt<MOD> mint;

struct UnionFind{
    vi data;
    UnionFind(int size):data(size,-1){}
    bool unite(int x,int y) {
        x=root(x);y=root(y);
        if(x!=y){
            if(data[y]<data[x])swap(x,y);
            data[x]+=data[y];data[y]=x;
        }
        return x!=y;
    }
    bool find(int x,int y) {
        return root(x)==root(y);
    }
    int root(int x) {
        return data[x]<0?x:data[x]=root(data[x]);
    }
    int size(int x) {
        return -data[root(x)];
    }
    // added by QCFium
    bool united() {
        int comroot = -1;
        FOR(i,data.size()) {
            if (comroot != -1 && root(i) != comroot) return false;
            comroot = root(i);
        }
        return true;
    }
};

/* ---------------------- */
/* END EXTERNAL LIBRARIES */
/* ---------------------- */

int mpow(s64 num, s64 times) { // O(log(times))
    mint next = num%MOD;
	mint res = 1;
	while (times) {
		if (times%2)
            res *= next;
		next *= next;
		times /= 2;
	}
	return res;
}

struct Comb {
    vector<vector<s64> > data;
    Comb(int n) { // O(n^2)
        data = vector<vector<s64> >(n+1,vector<s64>(n+1,1));
        UPTO(i,1,n) {
            FOR(j,i+1) {
                if (!j || j == i) data[i][j] = 1;
                else data[i][j] = data[i-1][j-1] + data[i-1][j];
            }
        }
    }
    
    s64 ncr(int n, int r) {
        return data[n][r];
    }
};

struct MComb {
    vector<mint> fact;
    vector<mint> inversed;
    MComb(int n) { // O(n+log(mod))
        fact = vector<mint>(n+1,1);
        UPTO(i,1,n) fact[i] = fact[i-1]*mint(i);
        inversed = vector<mint>(n+1);
        inversed[n] = mpow(fact[n], MOD-2);
        DOWN(i,n) inversed[i]=inversed[i+1]*mint(i+1);
    }
    
    int ncr(int n, int r) {
        return fact[n] * inversed[r] * inversed[n-r];
    }
    
    int npr(int n, int r) {
        return fact[n] * inversed[n-r];
    }
    
    int nhr(int n, int r) {
        assert(n+r-1 < (int)fact.size());
        return ncr(n+r-1, r);
    }
};

template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>>
set<Key> operator+(set<Key>& a, set<Key>& b) {
    set<Key> c = a;
    for (auto i : b) 
        c.insert(i);
    return c;
}
template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>>
set<Key> operator+=(set<Key>& a, set<Key>& b) {
    for (auto& i : b)
        a.insert(i);
    return a;
}

template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>>
set<Key> operator*(set<Key>& a, set<Key>& b) {
    set<Key> c;
    for (auto& i : a)
        if (b.count(i)) c.insert(i);
    return c;
}
template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>>
set<Key> operator*=(set<Key>& a, set<Key>& b) {
    set<Key> c;
    for (auto& i : a)
        if (b.count(i)) c.insert(i);
        
    return a = c;
}

template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>>
set<Key> operator-(set<Key>& a, set<Key>& b) {
    set<Key> c;
    for (auto& i : a)
        if (!b.count(i)) c.insert(i);
        
    return c;
}
template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>>
set<Key> operator-=(set<Key>& a, set<Key>& b) {
    set<Key> c;
    for (auto& i : a)
        if (!b.count(i)) c.insert(i);
        
    return a = c;
}

static inline int ri() {
  int a;
  scanf("%d", &a);
  return a;
}

int int_less(const void *a, const void *b) {
  return (*((const int*)a) - *((const int*)b));
}
int int_greater(const void *a, const void *b) {
  return (*((const int*)b) - *((const int*)a));
}
int b[2000][2000];
int bsum_tate[2000][2000];
int bsum_yoko[2000][2000];
int sum[2000][2000];

int main() {
	int n = ri();
	int k = ri();
	int w = 0;
	FOR(i,n) {
		int x = ri();
		int y = ri();
		char c; cin >> c;
		if (c == 'B') b[x%(2*k)][y%(2*k)]++;
		else          b[x%(2*k)][y%(2*k)]--, w++;
	}
	
	// YOKO
	FOR(i,2*k) {
		int bfirst = 0;
		FOR(j,k) bfirst += b[i][j], bfirst += b[(i+k)%(2*k)][(j+k)%(2*k)];
		FOR(j,2*k) {
			bsum_tate[i][j] = bfirst;
			bfirst += b[i][(j+k)%(2*k)];
			bfirst += b[(i+k)%(2*k)][j];
			bfirst -= b[i][j];
			bfirst -= b[(i+k)%(2*k)][(j+k)%(2*k)];
		}
	}
	
	/*
	cout << endl;
	FOR(i,2*k) {
		FOR(j,2*k) {
			cout << bsum_tate[i][j] << " ";
		}
		cout << endl;
	}
	cout << endl;*/
	
	// TATE
	FOR(i,2*k) {
		int bfirst = 0;
		FOR(j,k) bfirst += b[j][i], bfirst += b[(j+k)%(2*k)][(i+k)%(2*k)];
		FOR(j,2*k) {
			bsum_yoko[j][i] = bfirst;
			bfirst += b[(j+k)%(2*k)][i];
			bfirst += b[j][(i+k)%(2*k)];
			bfirst -= b[j][i];
			bfirst -= b[(j+k)%(2*k)][(i+k)%(2*k)];
		}
	}
	
	/*
	cout << endl;
	FOR(i,2*k) {
		FOR(j,2*k) {
			cout << bsum_yoko[i][j] << " ";
		}
		cout << endl;
	}
	cout << endl;*/
	
	FOR(i,2*k) {
		FOR(j,2*k) {
			if (i/k == j/k) {
				sum[0][0] += b[i][j];
			}
		}
	}
	UPTO(i,1,2*k-1) {
		sum[0][i] = sum[0][i-1];
		sum[0][i] += bsum_yoko[0][(i+k-1)%(2*k)];
		sum[0][i] -= bsum_yoko[0][(i-1+2*k)%(2*k)];
	}
	UPTO(i,1,2*k-1) {
		FOR(j,2*k) {
			sum[i][j] = sum[i-1][j];
			sum[i][j] += bsum_tate[(i+k-1)%(2*k)][j];
			sum[i][j] -= bsum_tate[(i-1+2*k)%(2*k)][j];
		}
	}
	
	int maxx = -INF;
	FOR(i,2*k) {
		FOR(j,2*k) {
			/*if (maxx < sum[i][j]) {
				cout << "i:" << i << " j:" << j <<  " updated to " << sum[i][j] << endl;
			}*/
			maxx = max(maxx, sum[i][j]);
		}
	}
	
	/*
	cout << endl;
	FOR(i,2*k) {
		FOR(j,2*k) {
			cout << sum[i][j] << " ";
		}
		cout << endl;
	}
	cout << endl;*/
	
	// cout << maxx << endl;
	cout << maxx + w << endl;
	
	
    return 0;
}