#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <deque>
#include <list>
#include <queue>
#include <stack>
#include <vector>
#include <utility>
#include <algorithm>
#include <map>
#include <set>
#include <complex>
#include <cmath>
#include <limits>
#include <climits>
#include <ctime>
#include <cassert>
#include <numeric>
#include <functional>
#include <bitset>

using namespace std;
using lint = long long int;
using ll = long long int;
using graph = vector<vector<int>>;
using wgraph = vector<vector<pair<int, lint>>>;
const lint INF = 1001001001001001LL;
const lint MOD = 1000000007LL;
const double PI = 3.1415926535897932;
int di[] = {-1, 0, 1, 0, -1, 1, 1, -1};
int dj[] = {0, 1, 0, -1, 1, 1, -1, -1};

void yes(){ cout << "yes" << endl; }
void Yes(){ cout << "Yes" << endl; }
void YES(){ cout << "YES" << endl; }
void no(){ cout << "no" << endl; }
void No(){ cout << "No" << endl; }
void NO(){ cout << "NO" << endl; }
void possible(){ cout << "possible" << endl; }
void Possible(){ cout << "Possible" << endl; }
void POSSIBLE(){ cout << "POSSIBLE" << endl; }
void impossible(){ cout << "impossible" << endl; }
void Impossible(){ cout << "Impossible" << endl; }
void IMPOSSIBLE(){ cout << "IMPOSSIBLE" << endl; }

#define rep(i,n) for(int i = 0; i < (n); i++)
#define rrep(i,n) for(int i = 1; i <= (n); i++)
#define drep(i,n) for(int i = (n)-1; i >= 0; i--)
#define srep(i,s,t) for(int i = s; i < t; i++)
#define all(a) a.begin(),a.end()
#define rall(a) a.rbegin(),a.rend()

// 抽象二次元累積和
// 構築 O(hw), get O(1)
// TODO verify (https://atcoder.jp/contests/arc089/tasks/arc089_b)

//       ^
//       u
//  <= l   r =>
//       d
//       v      

template<typename T>
struct RecSum{
private: 
  size_t h, w;
  vector<vector<T>> dat;

public: 
  RecSum(const vector<vector<T>> &v){
    h = v.size();
    w = v[0].size();
    dat.resize(h + 1);
    for(size_t i = 0; i < h + 1; i++) dat[i].resize(w + 1, 0);
    for(size_t i = 0; i < h; i++){
      for(size_t j = 0; j < w; j++){
        dat[i + 1][j + 1] = v[i][j] + dat[i + 1][j];
      }
    }
    for(size_t j = 0; j < w; j++){
      for(size_t i = 0; i < h; i++){
        dat[i + 1][j + 1] += dat[i][j + 1];
      }
    }
  }

  T get(size_t l, size_t r, size_t u, size_t d) const { // 0-indexed, [l, r), [u, d)
    return dat[d][r] - dat[u][r] - dat[d][l] + dat[u][l];
  }
};

int main(){
  
  lint n, k; cin >> n >> k;
  vector<vector<lint>> cntBlack(2 * k, vector<lint> (2 * k, 0));
  
  rep(i, n){
    lint x, y;
    char c; cin >> x >> y >> c;
    if(c == 'W') x += k;
    x %= 2 * k;
    y %= 2 * k;
    cntBlack[x][y]++;
  }

  RecSum<lint> rsBlack(cntBlack);

  lint ans = 0;
  rep(i, k){
    rep(j, k){
      lint cb = 0;
      lint ccb = rsBlack.get(0, 2 * k, 0, 2 * k);
      // 5 つの領域に分かれる?
      cb += rsBlack.get(0, i, 0, j);

      cb += rsBlack.get(i, i + k, j, j + k);
      
      cb += rsBlack.get(0, i, j + k, 2 * k);

      cb += rsBlack.get(i + k, 2 * k, 0, j);

      cb += rsBlack.get(i + k, 2 * k, j + k, 2 * k);
      
      ccb -= rsBlack.get(0, i, 0, j);

      ccb -= rsBlack.get(i, i + k, j, j + k);
      
      ccb -= rsBlack.get(0, i, j + k, 2 * k);

      ccb -= rsBlack.get(i + k, 2 * k, 0, j);

      ccb -= rsBlack.get(i + k, 2 * k, j + k, 2 * k);


      ans = max(ans, max(cb, ccb));
    }
  }
  
  cout << ans << endl;

  return 0;
}


Measured memory_bytes: 62976