10 10
.L.....R..
.........U
..D....D..
.R......L.
....L.....
.........D
......U...
D....R....
...U......
........L.
 5 5
DD..D
.....
LU...
U...U
.UL.U
 1 1
U
 5 5
UD..L
RRD..
..RDD
UUL..
DDLRR
 19 23
U..U..R........L...D...
.D.....UL.U.U........DR
..D.U..D....L......R...
D.......RL.L....D.....R
U..D.....U...U.L..D...U
...........L...........
U....U....D.U......LRR.
......RL...U...L.......
DLU..U......UU.U.U.D...
...........D....U......
U...DL......LL.....R...
...U..DD..........LD...
.R.........D.....UU...U
....D......R..........D
.L..........R.....L....
.R........L.LL....R....
..R...D........R....D..
.LR.R..LDU.DDRL......U.
...LL.....D.....DD.....
 11 29
URRUUDDLURLRDDLLRLDUDR.UDLLD.
LRRUDLUDLDULUDL.DURDRR.RRLLRR
D.DUDDURLRDDULDUDDUDDURRDLD.L
.RULURURRDLRRRLUUUU.RDLDLRRRL
.RLDDU.UUULUURURRLLUU.RLDRDUD
LRL.URRRDDURUURUDRRDLDDULRDRL
RLULDU.LRDUDRLDLRDDDDRUUDRDLL
DLUDURRDDUDLLDLLUURLDRUURRLUL
L.RRURRDDRRURRRDDUDRRDULR.LUR
LDLRULURRUULRDUUULLU.LLU.LLLL
DUURDULDDUDLRUUDRUULURLD.RL.U
 2 2
RD
UL
 1 10
LLLLLRRRRR
 3 3
...
...
..R
 17 13
...LD.UR.RUU.
LDLULDUDRRDRL
DD.RRLRUR.UD.
RU...D...LD..
.UR.R...URUUD
.RURD.RLR.D.R
.UUU.RU...UR.
UUUU.R.......
RL.LRU.UD.DUD
LD.DRURRLRDRL
.DR..UULUDDR.
LRLURRUUDDLUR
.LRDDLLR.L.DU
DRUDLLD.LRRU.
..DL.UDL.DUL.
U.DL..D..U.RD
RR.R...RL.L..

2 2
 4 1
 1 1
 8 3
 9 1
 94 1
 4 4
 5 2
 1 1
 24 2

#include <bits/stdc++.h>
using namespace std;
struct node {
  int x, y;
  char dir;
  node(int x = 0, int y = 0, char dir = 'U') {
    this->x = x;
    this->y = y;
    this->dir = dir;
  }
};
struct lsx {
  bool operator()(const node &n1, const node &n2) const { return n1.x < n2.x; }
};
struct lsy {
  bool operator()(const node &n1, const node &n2) const { return n1.y < n2.y; }
};
const int N = 5000;
vector<set<node, lsx> > setx;
vector<set<node, lsy> > sety;
bool nextx(const node &n, node &val) {
  set<node, lsx>::iterator it = setx[n.y].upper_bound(n);
  if (it == setx[n.y].end()) return false;
  val = *it;
  return true;
}
bool nexty(const node &n, node &val) {
  set<node, lsy>::iterator it = sety[n.x].upper_bound(n);
  if (it == sety[n.x].end()) return false;
  val = *it;
  return true;
}
bool prevx(const node &n, node &val) {
  set<node, lsx>::iterator it = setx[n.y].lower_bound(n);
  if (it == setx[n.y].begin()) return false;
  --it;
  val = *it;
  return true;
}
bool prevy(const node &n, node &val) {
  set<node, lsy>::iterator it = sety[n.x].lower_bound(n);
  if (it == sety[n.x].begin()) return false;
  --it;
  val = *it;
  return true;
}
void ins(const node &n) {
  setx[n.y].insert(n);
  sety[n.x].insert(n);
}
void del(const node &n) {
  setx[n.y].erase(n);
  sety[n.x].erase(n);
}
char s[N + 1];
vector<node> nodes;
vector<node> dels;
int n, m;
int main() {
  scanf("%d%d", &n, &m);
  setx.resize(m);
  sety.resize(n);
  for (int i = 0; i < n; i++) {
    scanf("%s", s);
    for (int j = 0; j < m; j++)
      if (s[j] != '.') {
        node t(i, j, s[j]);
        ins(t);
        nodes.push_back(t);
      }
  }
  int mx = 0, kol = 0;
  int k = min(10 * (int)nodes.size(), 1000);
  srand(k);
  for (int z = 0; z < k; z++) {
    int i = rand() % nodes.size();
    dels.clear();
    node t = nodes[i];
    dels.push_back(t);
    del(t);
    for (;;) {
      node nx;
      bool ok;
      switch (t.dir) {
        case 'U':
          ok = prevx(t, nx);
          break;
        case 'D':
          ok = nextx(t, nx);
          break;
        case 'R':
          ok = nexty(t, nx);
          break;
        case 'L':
          ok = prevy(t, nx);
          break;
      }
      if (!ok) break;
      t = nx;
      dels.push_back(t);
      del(t);
    }
    if (mx < dels.size()) {
      mx = dels.size();
      kol = 1;
    } else if (mx == dels.size())
      kol++;
    for (int i = 0; i < dels.size(); i++) ins(dels[i]);
  }
  printf("%d %d", mx, kol);
}
