Problem:
Score : 2718 points

Problem Statement

There is a very long bench.
The bench is divided into M sections, where M is a very large integer.

Initially, the bench is vacant.
Then, M people come to the bench one by one, and perform the following action:

We call a section comfortable if the section is currently unoccupied and is not adjacent to any occupied sections.
If there is no comfortable section, the person leaves the bench.
Otherwise, the person chooses one of comfortable sections uniformly at random, and sits there.
(The choices are independent from each other).

After all M people perform actions, Snuke chooses an interval of N consecutive sections uniformly at random (from M-N+1 possible intervals), and takes a photo.
His photo can be described by a string of length N consisting of X and -: the i-th character of the string is X if the i-th section from the left in the interval is occupied, and - otherwise.
Note that the photo is directed.
For example, -X--X and X--X- are different photos.

What is the probability that the photo matches a given string s?
This probability depends on M.
You need to compute the limit of this probability when M goes infinity.

Here, we can prove that the limit can be uniquely written in the following format using three rational numbers p, q, r and e = 2.718 \ldots (the base of natural logarithm):

p + \frac{q}{e} + \frac{r}{e^2}

Your task is to compute these three rational numbers, and print them modulo 10^9 + 7, as described in Notes section.

Notes

When you print a rational number, first write it as a fraction \frac{y}{x}, where x, y are integers and x is not divisible by 10^9 + 7
(under the constraints of the problem, such representation is always possible).
Then, you need to print the only integer z between 0 and 10^9 + 6, inclusive, that satisfies xz \equiv y \pmod{10^9 + 7}.

Constraints

1 \leq N \leq 1000

|s| = N

s consists of X and -.

Input

Input is given from Standard Input in the following format:

N
s

Output

Print three rational numbers p, q, r, separated by spaces.

Sample Input 1

1
X

Sample Output 1

500000004 0 500000003

The probability that a randomly chosen section is occupied converge to \frac{1}{2} - \frac{1}{2e^2}.

Sample Input 2

3
---

Sample Output 2

0 0 0

After the actions, no three consecutive unoccupied sections can be left.

Sample Input 3

5
X--X-

Sample Output 3

0 0 1

The limit is \frac{1}{e^2}.

Sample Input 4

5
X-X-X

Sample Output 4

500000004 0 833333337

The limit is \frac{1}{2} - \frac{13}{6e^2}.

Sample Input 5

20
-X--X--X-X--X--X-X-X

Sample Output 5

0 0 183703705

The limit is \frac{7}{675e^2}.

Sample Input 6

100
X-X-X-X-X-X-X-X-X-X--X-X-X-X-X-X-X-X-X-X-X-X-X-X-X--X--X-X-X-X--X--X-X-X--X-X-X--X-X--X--X-X--X-X-X-

Sample Output 6

0 0 435664291

Solution in C++14 (GCC 5.4.1) (judge verdict: Accepted)

#pragma GCC target("avx2")
#pragma GCC optimization("O3")
#pragma GCC optimization("unroll-loops")
#include <algorithm>
#include <assert.h>
#include <bitset>
#include <cfloat>
#include <complex>
#include <deque>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits.h>
#include <list>
#include <map>
#include <math.h>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <string.h>
#include <time.h>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#define rep(i,n) for(int i=0;i<(n);i++)
#define REP(i,n) for(int i=1;i<=(n);i++)
#define ll long long
#define P pair<int,int>
#define prique(T) priority_queue<T,vector<T>,greater<T>>
#define all(V) V.begin(),V.end()
#ifdef int
constexpr int INF = LLONG_MAX / 10;
#else
constexpr int INF = INT_MAX / 10;
#endif
constexpr double eps = 1e-9;
template <class T, class U>
inline bool chmax(T& lhs, const U& rhs) {
	if (lhs < rhs) {
		lhs = rhs;
		return 1;
	}
	return 0;
}
template <class T, class U>
inline bool chmin(T& lhs, const U& rhs) {
	if (lhs > rhs) {
		lhs = rhs;
		return 1;
	}
	return 0;
}
using namespace std;
inline ll gcd(ll a, ll b) {
	while (b) {
		ll c = a;
		a = b; b = c % b;
	}
	return a;
}
inline ll lcm(ll a, ll b) {
	return a / gcd(a, b) * b;
}
bool isprime(ll n) {
	if (n == 1)return false;
	for (int i = 2; i * i <= n; i++) {
		if (n % i == 0)return false;
	}
	return true;
}
ll mypow(ll a, ll b) {
	if (!b)return 1;
	if (b & 1)return mypow(a, b - 1) * a;
	int memo = mypow(a, b >> 1);
	return memo * memo;
}
constexpr int mod = 1000000007;
class modInt {
	ll value;
public:
	modInt() : value(0) {}
	template<typename T>
	modInt(T value = 0) : value(value) {
		if (value < 0)value = -(-value % mod) + mod;
		this->value = value % mod;
	}
	inline operator int()const { return value; }
	inline modInt& operator+=(const modInt& x) {
		value += x.value;
		if (value >= mod)value -= mod;
		return *this;
	}
	inline modInt& operator++() {
		if (value == mod - 1)value = 0;
		else value++;
		return *this;
	}
	inline modInt operator-()const {
		return modInt(0) -= *this;
	}
	inline modInt& operator-=(const modInt& x) {
		value -= x.value;
		if (value < 0)value += mod;
		return *this;
	}
	inline modInt& operator--() {
		if (value == 0)value = mod - 1;
		else value--;
		return *this;
	}
	inline modInt& operator*=(const modInt& x) {
		value = value * x.value % mod;
		return *this;
	}
	inline modInt& operator/=(modInt rhs) {
		int exp = mod - 2;
		while (exp) {
			if (exp & 1)*this *= rhs;
			rhs *= rhs;
			exp >>= 1;
		}
		return *this;
	}
	template<typename T> modInt operator+(T x)const { return modInt(*this) += x; }
	template<typename T> modInt& operator+=(T x) { return operator+=(modInt(x)); }
	template<typename T> modInt operator-(T x)const { return modInt(*this) -= x; }
	template<typename T> modInt& operator-=(T x) { return operator-=(modInt(x)); }
	template<typename T> modInt operator*(T x)const { return modInt(*this) *= x; }
	template<typename T> modInt& operator*=(T x) { return operator*=(modInt(x)); }
	template<typename T> modInt operator/(T x)const { return modInt(*this) /= x; }
	template<typename T> modInt& operator/=(T x) { return operator/=(modInt(x)); }
};
istream& operator>>(istream& ist, modInt& x) {
	ll a;
	ist >> a;
	x = a;
	return ist;
}
modInt modpow(modInt a, ll b) {
	if (!b)return modInt(1);
	if (b & 1)return modpow(a, b - 1) * a;
	modInt memo = modpow(a, b / 2);
	return memo * memo;
}
class Polynomial {
public:
	vector<modInt> vec;
	Polynomial() {}
	Polynomial(const vector<modInt>& vec) :vec(vec) {}
	modInt get(const modInt& x) {
		modInt res = 0;
		rep(i, vec.size()) {
			res += modpow(x, i) * vec[i];
		}
		return res;
	}
	Polynomial integrate()const {
		vector<modInt> res = vec;
		res.emplace_back();
		for (int i = (int)res.size() - 2; i >= 0; i--)res[i + 1] = res[i] / (i + 1);
		res[0] = 0;
		return Polynomial(res);
	}
	Polynomial& operator+=(const Polynomial& rhs) {
		vec.resize(max(vec.size(), rhs.vec.size()));
		rep(i, rhs.vec.size())vec[i] += rhs.vec[i];
		return *this;
	}
};
class func {
public:
	Polynomial first, second;
	modInt third;
	func() {}
	func(const Polynomial& first, const Polynomial& second, const modInt& third) :first(first), second(second), third(third) {}
	void set(const Polynomial& first, const Polynomial& second, const modInt& third) {
		this->first = first;
		this->second = second;
		this->third = third;
	}
	func& operator+=(const func& f) {
		first += f.first;
		second += f.second;
		third += f.third;
		return *this;
	}
};
func dintegrate(const func& f, bool flag) {
	Polynomial p = f.first.integrate(), q = f.second.integrate();
	if (!flag) {
		p.vec[0] = f.third;
		return func(p, q, -f.third);
	}
	else {
		p.vec[0] -= p.get(1);
		rep(i, p.vec.size())p.vec[i] = -p.vec[i];
		q.vec[0] -= q.get(1);
		q.vec[0] += f.third;
		rep(i, q.vec.size())q.vec[i] = -q.vec[i];
		return func(p, q, f.third);
	}
}
int n;
string s;
func dp[1010][2][2][2];
modInt fact[1010], inv[1010];
signed main() {
	cin >> n >> s;
	fact[0] = 1;
	REP(i, n)fact[i] = fact[i - 1] * i;
	inv[n] = modInt(1) / fact[n];
	for (int i = n - 1; i >= 0; i--)inv[i] = inv[i + 1] * (i + 1);
	if (s[0] == 'X')dp[0][0][1][0].set(vector<modInt>(), vector<modInt>(), 1);
	else {
		dp[0][0][0][1].set(vector<modInt>(), vector<modInt>(), 1);
		dp[0][1][1][1].set(vector<modInt>(1, 1), vector<modInt>(), modInt(-1));
	}
	REP(i, n - 1) {
		if (s[i] == 'X') {
			dp[i][0][1][0] += dintegrate(dp[i - 1][1][1][0], 0);
			dp[i][0][1][0] += dintegrate(dp[i - 1][1][1][1], 0);
			dp[i][0][1][0] += dintegrate(dp[i - 1][0][0][1], 1);
			dp[i][0][1][0] += dintegrate(dp[i - 1][0][1][1], 1);
			dp[i][0][1][0] += dintegrate(dp[i - 1][1][0][1], 1);
			dp[i][0][1][0] += dintegrate(dp[i - 1][1][1][1], 1);
		}
		else {
			dp[i][0][0][1] += dintegrate(dp[i - 1][1][1][0], 0);
			dp[i][0][0][1] += dintegrate(dp[i - 1][1][1][1], 0);
			dp[i][1][1][1] += dintegrate(dp[i - 1][0][1][0], 0);
			dp[i][1][1][1] += dintegrate(dp[i - 1][0][1][1], 0);
			dp[i][0][0][1] += dintegrate(dp[i - 1][0][1][0], 1);
			dp[i][0][0][1] += dintegrate(dp[i - 1][0][1][1], 1);
			dp[i][0][0][1] += dintegrate(dp[i - 1][1][1][0], 1);
			dp[i][0][0][1] += dintegrate(dp[i - 1][1][1][1], 1);
		}
	}
	modInt a, b, c;
	Polynomial p;

	p = dp[n - 1][0][1][1].first.integrate();
	a += p.get(1) - p.get(0);
	p = dp[n - 1][0][1][1].second.integrate();
	b += p.get(1) - p.get(0);
	a += dp[n - 1][0][1][1].third;
	b -= dp[n - 1][0][1][1].third;
	p = dp[n - 1][1][1][1].first.integrate();
	a += p.get(1) - p.get(0);
	p = dp[n - 1][1][1][1].second.integrate();
	b += p.get(1) - p.get(0);
	a += dp[n - 1][1][1][1].third;
	b -= dp[n - 1][1][1][1].third;

	rep(i, dp[n - 1][0][1][0].first.vec.size()) {
		a += dp[n - 1][0][1][0].first.vec[i] * fact[i];
		rep(j, i + 1) {
			b -= dp[n - 1][0][1][0].first.vec[i] * fact[i] * inv[j];
		}
	}
	rep(i, dp[n - 1][0][1][0].second.vec.size()) {
		b += dp[n - 1][0][1][0].second.vec[i] * fact[i];
		rep(j, i + 1) {
			c -= dp[n - 1][0][1][0].second.vec[i] * fact[i] * inv[j];
		}
	}
	a += dp[n - 1][0][1][0].third / 2;
	c -= dp[n - 1][0][1][0].third / 2;

	rep(i, dp[n - 1][1][1][0].first.vec.size()) {
		a += dp[n - 1][1][1][0].first.vec[i] * fact[i];
		rep(j, i + 1) {
			b -= dp[n - 1][1][1][0].first.vec[i] * fact[i] * inv[j];
		}
	}
	rep(i, dp[n - 1][1][1][0].second.vec.size()) {
		b += dp[n - 1][1][1][0].second.vec[i] * fact[i];
		rep(j, i + 1) {
			c -= dp[n - 1][1][1][0].second.vec[i] * fact[i] * inv[j];
		}
	}
	a += dp[n - 1][1][1][0].third / 2;
	c -= dp[n - 1][1][1][0].third / 2;

	p = dp[n - 1][0][0][1].first.integrate();
	a += p.get(1) - p.get(0);
	p = dp[n - 1][0][0][1].second.integrate();
	b += p.get(1) - p.get(0);
	a += dp[n - 1][0][0][1].third;
	b -= dp[n - 1][0][0][1].third;
	p = dp[n - 1][1][0][1].first.integrate();
	a += p.get(1) - p.get(0);
	p = dp[n - 1][1][0][1].second.integrate();
	b += p.get(1) - p.get(0);
	a += dp[n - 1][1][0][1].third;
	b -= dp[n - 1][1][0][1].third;

	rep(i, dp[n - 1][0][0][1].first.vec.size()) {
		a -= dp[n - 1][0][0][1].first.vec[i] * fact[i];
		rep(j, i + 1) {
			b += dp[n - 1][0][0][1].first.vec[i] * fact[i] * inv[j];
		}
	}
	rep(i, dp[n - 1][0][0][1].second.vec.size()) {
		b -= dp[n - 1][0][0][1].second.vec[i] * fact[i];
		rep(j, i + 1) {
			c += dp[n - 1][0][0][1].second.vec[i] * fact[i] * inv[j];
		}
	}
	a -= dp[n - 1][0][0][1].third / 2;
	c += dp[n - 1][0][0][1].third / 2;

	rep(i, dp[n - 1][1][0][1].first.vec.size()) {
		a -= dp[n - 1][1][0][1].first.vec[i] * fact[i];
		rep(j, i + 1) {
			b += dp[n - 1][1][0][1].first.vec[i] * fact[i] * inv[j];
		}
	}
	rep(i, dp[n - 1][1][0][1].second.vec.size()) {
		b -= dp[n - 1][1][0][1].second.vec[i] * fact[i];
		rep(j, i + 1) {
			c += dp[n - 1][1][0][1].second.vec[i] * fact[i] * inv[j];
		}
	}
	a -= dp[n - 1][1][0][1].third / 2;
	c += dp[n - 1][1][0][1].third / 2;

	cout << a << " " << 0 << " " << c << endl;
	return 0;
}