#include <bits/stdc++.h>

using namespace std;
#define rep(i,n) for(int i=0;i<n;++i)
#define rep1(i,n) for(int i=1;i<=n;++i)
#define debug(output) if(debugFlag)cout<<#output<<"= "<<output<<endl
using lint = long long;
typedef pair<int,int> P;
const bool debugFlag=true;
const lint linf=1e18+7;
const lint inf=1e9+7;
const int MOD=1000000007;
struct UnionFind {
    int n;
    vector<int> par; // par[i]:iの親の番号　(例) par[3] = 2 : 3の親が2
    vector<int> group,sm;
    UnionFind(int N) : par(N) { //最初は全てが根であるとして初期化
        for(int i = 0; i < N; i++) par[i] = i;
        n=N;
        sm.resize(n,1);
    }
    int root(int x) { // データxが属する木の根を再帰で得る：root(x) = {xの木の根}
        if (par[x] == x) return x;
        return par[x] = root(par[x]);
    }
    int size(int x){
        return sm[root(x)];
    }
    void unite(int x, int y) { // xとyの木を併合
        int rx = root(x); //xの根をrx
        int ry = root(y); //yの根をry
        if (rx == ry) return; //xとyの根が同じ(=同じ木にある)時はそのまま
        par[rx] = ry; //xとyの根が同じでない(=同じ木にない)時：xの根rxをyの根ryにつける
        sm[ry]+=sm[rx];
        sm[rx]=0;
    }
    bool same(int x, int y) { // 2つのデータx, yが属する木が同じならtrueを返す
        int rx = root(x);
        int ry = root(y);
        return rx == ry;
    }
};
signed main(){
  int h,w;cin>>h>>w;
  UnionFind tree(h+w+10);
  vector<string> s(h);
  rep(i,h)cin>>s[i];
  s[0][0]='#';
  s[h-1][0]='#';
  s[0][w-1]='#';
  s[h-1][w-1]='#';
  rep(i,h)rep(j,w)if(s[i][j]=='#')tree.unite(i,h+j);
  int res=inf;
  int sm=0;
  set<int> st;
  rep(i,h){
      if(!tree.same(0,i)){
          if(st.find(tree.root(i))==st.end()){
              st.insert(tree.root(i));
              ++sm;
          }
      }
  }
  res=min(res,sm);
  sm=0;
  set<int> st2;
  rep(i,w){
      if(!tree.same(0,h+i)){
          if(st2.find(tree.root(h+i))==st2.end()){
              st2.insert(tree.root(h+i));
              ++sm;
          }
      }
  }
  res=min(res,sm);
  cout<<res<<"\n";
  return 0;
}
#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<ll, ll> p_ll;

template<class T>
void debug(T itr1, T itr2) { auto now = itr1; while(now<itr2) { cout << *now << " "; now++; } cout << endl; }
#define repr(i,from,to) for (ll i=(ll)from; i<(ll)to; i++)
#define all(vec) vec.begin(), vec.end()
#define rep(i,N) repr(i,0,N)
#define per(i,N) for (ll i=(ll)N-1; i>=0; i--)
#define popcount __builtin_popcount

const ll LLINF = pow(2,61)-1;
const ll INF = pow(2,30)-1;

ll gcd(ll a, ll b) { if (a<b) swap(a,b); return b==0 ? a : gcd(b, a%b); }
ll lcm(ll a, ll b) { return a/gcd(a,b)*b; }

// ----------------------------------------------------------------------
// ----------------------------------------------------------------------

const ll MOD = 998244353;
struct MLL {
  ll x, mod;
  MLL(ll y=0, ll m=MOD) { x = y; mod = m; }

  MLL &operator+= (const MLL &p) { x = (x+p.x)%mod;       return *this; }
  MLL &operator-= (const MLL &p) { x = (x-p.x+mod)%mod;   return *this; }
  MLL &operator*= (const MLL &p) { x = (x*p.x)%mod;       return *this; }
  MLL &operator/= (const MLL &p) { x = (x*p.inv().x)%mod; return *this; }
  MLL  operator+  (const MLL &p) const { return MLL(*this)+=p; }
  MLL  operator-  (const MLL &p) const { return MLL(*this)-=p; }
  MLL  operator*  (const MLL &p) const { return MLL(*this)*=p; }
  MLL  operator/  (const MLL &p) const { return MLL(*this)/=p; }
  bool operator== (const MLL &p) const { return x==p.x; }
  bool operator!= (const MLL &p) const { return x!=p.x; }
  bool operator<  (const MLL &p) const { return x< p.x; }
  bool operator<= (const MLL &p) const { return x<=p.x; }
  bool operator>  (const MLL &p) const { return x> p.x; }
  bool operator>= (const MLL &p) const { return x>=p.x; }
  MLL pow(MLL n) const { MLL result(1), p(x); ll tn = n.x; while(tn){ if (tn&1) result*=p; p*=p; tn>>=1; } return result; }
  MLL inv() const { return pow(MOD-2); }
};

MLL operator+ (ll x, MLL p) { return (MLL)x+p; }
MLL operator- (ll x, MLL p) { return (MLL)x-p; }
MLL operator* (ll x, MLL p) { return (MLL)x*p; }
MLL operator/ (ll x, MLL p) { return (MLL)x/p; }

vector<MLL> fac;
void c_fac(ll x=pow(10,7)+10) { fac.resize(x); rep(i,x) fac[i] = i ? fac[i-1]*i : 1; }
MLL nck(MLL n, MLL k) { return fac[n.x]/(fac[k.x]*fac[(n-k).x]); };

ostream &operator<< (ostream &ost, const MLL &p) { return ost << p.x; }
istream &operator>> (istream &ist, MLL &p) { return ist >> p.x; }

// ----------------------------------------------------------------------
// ----------------------------------------------------------------------

int main() {
  ll H, W, K; cin >> H >> W >> K;
  ll pos[H][W] = {};
  rep(i,K) {
    ll h, w; cin >> h >> w; h--; w--;
    char c; cin >> c;
    if (c=='R') pos[h][w] = 1;
    if (c=='D') pos[h][w] = 2;
    if (c=='X') pos[h][w] = 3;
  }
  // rep(i,H) debug(pos[i],pos[i]+W);

  MLL dp[H][W] = {}; dp[0][0] = 1;
  MLL m3 = 3, inv3 = m3.inv();
  rep(i,H) rep(j,W) {
    if (i!=H-1) {
      if (pos[i][j]==0) dp[i+1][j] += dp[i][j]*2*inv3;
      if (pos[i][j]==1) dp[i+1][j] += dp[i][j]*0;
      if (pos[i][j]==2) dp[i+1][j] += dp[i][j]*1;
      if (pos[i][j]==3) dp[i+1][j] += dp[i][j]*1;
    }
    if (j!=W-1) {
      if (pos[i][j]==0) dp[i][j+1] += dp[i][j]*2*inv3;
      if (pos[i][j]==1) dp[i][j+1] += dp[i][j]*1;
      if (pos[i][j]==2) dp[i][j+1] += dp[i][j]*0;
      if (pos[i][j]==3) dp[i][j+1] += dp[i][j]*1;
    }
  }
  // rep(i,H) debug(dp[i],dp[i]+W);

  MLL result = dp[H-1][W-1]*m3.pow(H*W-K);
  cout << result << endl;
  return 0;
}