#include <fstream>
#include <vector>
#include <string>
#include <algorithm>
#include <map>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <queue>
using namespace std;

ifstream cin("robots.in");
ofstream cout("robots.out");

#define pb push_back
#define vec vector
#define rep(k, l, r) for (int k = (int)(l); k < (int)(r); k++)
typedef long long ll;
typedef pair<ll, ll> PII;

int dx[4] = { 1, 0, -1, 0 };
int dy[4] = { 0, 1, 0, -1 };
vec<string> table;
vec<int> robots, marked;
vec<vec<int> > g, gr, r, dist, cycle;
vec<char> used, is_robot;
int n, m, p, ind = 1;

bool up(char c) {
	return c >= 'A' && c <= 'Z';
}

char to_up(char c) {
	if (c >= 'a' && c <= 'z') { return c - 'a' + 'A'; }
	return c;
}

int dir(char c) {
	if (c == 'N') { return 2; }
	if (c == 'S') { return 0; }
	if (c == 'E') { return 1; }
	return 3;
}

bool in_range(int x, int y, int n, int m) {
	return x >= 0 && y >= 0 && x < n && y < m;
}

void gen_test() {
	int n = rand() % 10 + 1, m = rand() % 10 + 1;
	cout << n << " " << m << " 0\n";
	string s = "SENW";
	rep(k, 0, n) {
		rep(i, 0, m) {
			int j;
			do {
				j = rand() % 4;
			} while (!in_range(k + dx[j], i + dy[j], n, m));
			cout << s[j];
		}
		cout << '\n';
	}
}

vec<int> c;
void search(int v) {
	if (marked[v] != 0) { return; }
	if (!c.empty() && c[0] == v) { return; }
	if (used[v]) { c.push_back(v); }
	used[v] = true;
	search(g[v][0]);
}

void dfs(int v, int num, int k) {
	if (marked[v] != 0) {
		r[v].push_back(k);
		dist[v].push_back(num);
		return;
	}
	dfs(g[v][0], num + 1, k);
}

int main() {
	srand(time(0));
	ios_base::sync_with_stdio(false);
	//gen_test();
	cin >> n >> m >> p;
	dist = r = g = gr = vec<vec<int> >(n * m);
	is_robot = used = vec<char>(n * m, false);
	marked = vec<int>(n * m, 0);
	rep(k, 0, n) {
		string s;
		cin >> s;
		rep(i, 0, m) {
			if (up(s[i])) { robots.push_back(k * m + i); is_robot[k * m + i] = true; }
			s[i] = to_up(s[i]);
			int v = k * m + i;
			int u = (k + dx[dir(s[i])]) * m + i + dy[dir(s[i])];
			g[v].push_back(u);
			gr[u].push_back(v);
		}
	}
	rep(k, 0, robots.size()) {
		search(robots[k]);
		rep(i, 0, c.size()) { marked[c[i]] = true; }
		used.assign(n * m, false);
		dfs(robots[k], 0, k);
		used.assign(n * m, false);
		cycle.push_back(c);
		c.clear();
	}
	if (p == 0 && robots.size() == n * m) {
		int sum = 0;
		rep(k, 0, cycle.size()) {
			sum += cycle[k].size();
		}
		cout << sum << '\n';
		return 0;
	}
	vec<int> in(robots.size(), -1), out(robots.size());
	rep(k, 0, cycle.size()) {
		int rem = cycle[k].size();
		int last_dist = -1, last_k = -1, last_v = -1;
		int last_i = -1;
		rep(i, 0, cycle[k].size()) {
			int v = cycle[k][i];
			if (rem == 0) { break; }
			rep(j, 0, dist[v].size()) {
				if (rem == 0) { break; }
				if (rem == cycle[k].size()) {
					in[r[v][j]] = 0; 
					rem--; last_dist = dist[v][j]; last_k = r[v][j];
					last_i = i;
					continue;
				}
				int q = i - dist[v][j] - 1;
				while (q < 0) { q += cycle[k].size(); }
				in[r[v][j]] = in[last_k] + last_dist + (cycle[k].size() + i - last_i) % cycle[k].size();
				rem--;
				last_dist = dist[v][j];
				last_k = r[v][j];
				last_i = i;
			}
		}
	}
	int am = 0;
	rep(k, 0, robots.size()) { if (in[k] != -1) { am++; } }
	cout << am << '\n';
	if (p == 0) { return 0; }

	rep(k, 0, robots.size()) {
		if (in[k] != -1) {
			cout << robots[k] / m + 1 << " " << robots[k] % m + 1 << " " << in[k] + 1 << '\n';
		}
	}
	return 0;
}