import std.conv, std.functional, std.stdio, std.string;
import std.algorithm, std.array, std.bigint, std.complex, std.container, std.math, std.numeric, std.range, std.regex, std.typecons;
import core.bitop;

class EOFException : Throwable { this() { super("EOF"); } }
string[] tokens;
string readToken() { for (; tokens.empty; ) { if (stdin.eof) { throw new EOFException; } tokens = readln.split; } auto token = tokens.front; tokens.popFront; return token; }
int readInt() { return readToken.to!int; }
long readLong() { return readToken.to!long; }
real readReal() { return readToken.to!real; }

bool chmin(T)(ref T t, in T f) { if (t > f) { t = f; return true; } else { return false; } }
bool chmax(T)(ref T t, in T f) { if (t < f) { t = f; return true; } else { return false; } }

int binarySearch(alias pred, T)(in T[] as) { int lo = -1, hi = cast(int)(as.length); for (; lo + 1 < hi; ) { const mid = (lo + hi) >> 1; (unaryFun!pred(as[mid]) ? hi : lo) = mid; } return hi; }
int lowerBound(T)(in T[] as, T val) { return as.binarySearch!(a => (a >= val)); }
int upperBound(T)(in T[] as, T val) { return as.binarySearch!(a => (a > val)); }


enum MO = 10L^^9 + 7;
enum LIM = 3000;

long[] inv, fac, invFac;
void prepare() {
  inv = new long[LIM];
  fac = new long[LIM];
  invFac = new long[LIM];
  inv[1] = 1;
  foreach (i; 2 .. LIM) {
    inv[i] = MO - ((MO / i) * inv[cast(size_t)(MO % i)]) % MO;
  }
  fac[0] = invFac[0] = 1;
  foreach (i; 1 .. LIM) {
    fac[i] = (fac[i - 1] * i) % MO;
    invFac[i] = (invFac[i - 1] * inv[i]) % MO;
  }
}

/*
  Int[0..t] exp(-s) ds = - exp(-t) + 1
  Int[t..1] exp(-s) ds = - exp(-1) + exp(-t)
*/
// Fun(p, q, r) = p + q exp(-1) + r exp(-t)
struct Fun {
  long[] p, q;
  long r;
  Fun opBinary(string op)(in Fun f) const if (op == "+") {
    long[] pp = new long[max(p.length, f.p.length)];
    long[] qq = new long[max(q.length, f.q.length)];
    long rr;
    pp[0 .. p.length] += p[];
    pp[0 .. f.p.length] += f.p[];
    pp[] %= MO;
    qq[0 .. q.length] += q[];
    qq[0 .. f.q.length] += f.q[];
    qq[] %= MO;
    rr += r;
    rr += f.r;
    rr %= MO;
    debug {
      // writefln("%s + %s = %s", this, f, Fun(pp, qq, rr));
    }
    return Fun(pp, qq, rr);
  }
  ref Fun opOpAssign(string op)(in Fun f) if (op == "+") {
    return this = this + f;
  }
  Fun integrate0() const {
    long[] pp = new long[p.length + 1];
    long[] qq = new long[q.length + 1];
    long rr;
    foreach (d; 0 .. p.length) {
      pp[d + 1] += inv[d + 1] * p[d];
      pp[d + 1] %= MO;
    }
    foreach (d; 0 .. q.length) {
      qq[d + 1] += inv[d + 1] * q[d];
      qq[d + 1] %= MO;
    }
    pp[0] += r;
    pp[0] %= MO;
    rr = -r;
    debug {
      // writefln("Int0 %s = %s", this, Fun(pp, qq, rr));
    }
    return Fun(pp, qq, rr);
  }
  Fun integrate1() const {
    long[] pp = new long[p.length + 1];
    long[] qq = new long[q.length + 1];
    long rr;
    foreach (d; 0 .. p.length) {
      pp[0] += inv[d + 1] * p[d];
      pp[0] %= MO;
      pp[d + 1] -= inv[d + 1] * p[d];
      pp[d + 1] %= MO;
    }
    foreach (d; 0 .. q.length) {
      qq[0] += inv[d + 1] * q[d];
      qq[0] %= MO;
      qq[d + 1] -= inv[d + 1] * q[d];
      qq[d + 1] %= MO;
    }
    qq[0] -= r;
    qq[0] %= MO;
    rr = r;
    debug {
      // writefln("Int1 %s = %s", this, Fun(pp, qq, rr));
    }
    return Fun(pp, qq, rr);
  }
}
enum ZERO = Fun([0], [0], 0);

int N;
string S;

void main() {
  prepare();
  auto sumInvFac = new long[LIM];
  sumInvFac[0] = 1;
  foreach (i; 1 .. LIM) {
    sumInvFac[i] = (sumInvFac[i - 1] + invFac[i]) % MO;
  }
  
  try {
    for (; ; ) {
      N = readInt();
      S = readToken();
      
      // up-run, down-constraints
      auto DP = new Fun[][][](N, 2, 4);
      auto dp = new Fun[][][](N, 2, 4);
      foreach (i; 0 .. N) {
        foreach (a; 0 .. 2) {
          DP[i][a][] = ZERO;
          dp[i][a][] = ZERO;
        }
      }
      DP[0][0][3] = Fun([0], [0], 1);
      DP[0][1][3] = Fun([1], [0], -1);
      foreach (i; 0 .. N) {
        foreach (a; 0 .. 2) foreach (c; 0 .. 4) {
          const cc = c & ((S[i] == 'X') ? ((a == 0) ? 1 : 0) : ((a == 0) ? 2 : 3));
          dp[i][a][cc] += DP[i][a][c];
        }
        debug {
          foreach (a; 0 .. 2) {
            writefln("DP[%s][%s] = %s", i, a, DP[i][a]);
          }
          foreach (a; 0 .. 2) {
            writefln("dp[%s][%s] = %s", i, a, dp[i][a]);
          }
        }
        if (i < N - 1) {
          foreach (a; 0 .. 2) foreach (c; 0 .. 4) {
            // <
            if (c & 1) {
              DP[i + 1][a ^ 1][3] += dp[i][a][c].integrate0;
            }
            // >
            {
              const cc = [0, 2, 1, 3][c];
              DP[i + 1][0][cc] += dp[i][a][c].integrate1;
            }
          }
        }
      }
      
      auto f = [ZERO, ZERO];
      foreach (a; 0 .. 2) foreach (c; 0 .. 4) {
        foreach (r; 0 .. 2) {
          if ((c >> r) & 1) {
            f[r] += dp[N - 1][a][c];
          }
        }
      }
      debug {
        writeln("f = ", f);
      }
      /*
        Int[0..1] x^d dt = 1 / (d + 1)
        Int[0..1] x^d exp(-t) dt = d! - d! (1/0! + ... + 1/d!) exp(-1)
        Int[0..1] exp(-t) dt = 1 - exp(-1)
        Int[0..1] exp(-t) exp(-t) dt = 1/2 - (1/2) exp(-2)
      */
      long[3] ans;
      
      // Int[0..1] f[0] exp(-t) dt
      foreach (d; 0 .. f[0].p.length) {
        ans[0] += fac[d] * f[0].p[d];
        ans[0] %= MO;
        ans[1] -= ((fac[d] * sumInvFac[d]) % MO) * f[0].p[d];
        ans[1] %= MO;
      }
      foreach (d; 0 .. f[0].q.length) {
        ans[1] += fac[d] * f[0].q[d];
        ans[1] %= MO;
        ans[2] -= ((fac[d] * sumInvFac[d]) % MO) * f[0].q[d];
        ans[2] %= MO;
      }
      ans[0] += inv[2] * f[0].r;
      ans[0] %= MO;
      ans[2] -= inv[2] * f[0].r;
      ans[2] %= MO;
      
      // Int[0..1] f[1] (1 - exp(-t)) dt
      foreach (d; 0 .. f[1].p.length) {
        ans[0] += inv[d + 1] * f[1].p[d];
        ans[0] %= MO;
        ans[0] -= fac[d] * f[1].p[d];
        ans[0] %= MO;
        ans[1] += ((fac[d] * sumInvFac[d]) % MO) * f[1].p[d];
        ans[1] %= MO;
      }
      foreach (d; 0 .. f[1].q.length) {
        ans[1] += inv[d + 1] * f[1].q[d];
        ans[1] %= MO;
        ans[1] -= fac[d] * f[1].q[d];
        ans[1] %= MO;
        ans[2] += ((fac[d] * sumInvFac[d]) % MO) * f[1].q[d];
        ans[2] %= MO;
      }
      ans[0] += f[1].r;
      ans[0] %= MO;
      ans[1] -= f[1].r;
      ans[1] %= MO;
      ans[0] -= inv[2] * f[1].r;
      ans[0] %= MO;
      ans[2] += inv[2] * f[1].r;
      ans[2] %= MO;
      
      ans[0] = (ans[0] % MO + MO) % MO;
      ans[1] = (ans[1] % MO + MO) % MO;
      ans[2] = (ans[2] % MO + MO) % MO;
      writeln(ans[0], " ", ans[1], " ", ans[2]);
    }
  } catch (EOFException e) {
  }
}


Measured memory_bytes: 85244