111
#include<bits/stdc++.h>
using namespace std;
const int mod = 998244353;
int Add(int x, int y) {
return (x += y) >= mod ? x - mod : x;
}
int Sub(int x, int y) {
return (x -= y) < 0 ? x + mod : x;
}
int Mul(int x, int y) {
return 1ll * x * y % mod;
}
string eq[15][2], e;
int n, tot;
struct Dsu {
int fa[26], can[26];
void Init() {
for(int i = 0; i < 26; ++ i)
fa[i] = i, can[i] = (1 << 10) - 1;
}
int Get(int x) {
return x == fa[x] ? x : fa[x] = Get(fa[x]);
}
int Set(int id, int l, int r) {
int p = Get(id), to = 0;
for(int i = l; i <= r; ++ i)
to |= 1 << i;
can[p] &= to;
return can[p];
}
int Merge(int u, int v) {
int x = Get(u), y = Get(v);
if(x == y)
return 1;
fa[y] = x;
can[x] &= can[y];
return can[x];
}
}d;
int ans, clk, to[26][26], deg[26], out[26], ways[26][10], vis[26], id[26];
vector<int> G[26];
queue<int>q;
int ffa[26], compid[26];
int Gget(int x) {
return x == ffa[x] ? x : ffa[x] = Gget(ffa[x]);
}
void Outmerge(int x, int y) {
ffa[Gget(y)] = Gget(x);
}
vector<int> idx[26];
int lesser[26], toid[26], canid[26];
int dp[(1 << 12) + 5][10];
int state_less[(1 << 12) + 5];
int canplace[(1 << 12) + 5];
void Calc(Dsu &now, vector<vector<int> > &less) {
cerr << "One Calc: ";
for(int i = 0; i < 26; ++ i) {
cerr << char(now.Get(i) + 'A') << " ";
}
cerr << endl;
for(int i = 0; i < 26; ++ i) {
if(now.Get(i) == i) {
cerr << "letter " << char(i + 'A') << ": ";
for(int j = 0; j < 10; ++ j)
cerr << (now.can[i] >> j & 1);
cerr << endl;
}
}
for(int i = 0; i < 26; ++ i)
ffa[i] = i;
++ clk;
for(int i = 0; i < 26; ++ i) {
deg[i] = out[i] = 0;
G[i].clear();
}
for(int i = 0; i < 26; ++ i) {
for(auto v : less[i]) {
int x = now.Get(i), y = now.Get(v);
if(x == y)
return;
if(to[x][y] != clk) {
to[x][y] = clk;
cerr << "Constraint: " << char(x + 'A') << " < " << char(y + 'A') << " " << x << " -> " << y << endl;
G[x].push_back(y);
Outmerge(x, y);
++ deg[y];
out[x] = 1;
}
}
}
int nowid = 0;
for(int i = 0; i < 26; ++ i) {
if(now.Get(i) != i) {
continue;
}
if(Gget(i) == i) {
idx[nowid].clear();
compid[i] = nowid ++;
}
}
for(int i = 0; i < 26; ++ i) {
if(now.Get(i) != i) {
continue;
}
// cerr << i << " fa = " << Gget(i) << " ";
idx[compid[Gget(i)]].push_back(i);
}
// cerr << endl;
int mul = 1;
for(int i = 0; i < nowid; ++ i) {
int totid = 0;
for(auto x : idx[i]) {
lesser[totid] = 0;
canid[totid] = now.can[x];
toid[x] = totid ++;
// cerr << x << ": ";
// for(auto v : G[x])
// cerr << v << " ";
// cerr << endl;
}
// cerr << endl;
for(auto x : idx[i])
if(!deg[x])
q.push(x);
int sz = 0;
while(!q.empty()) {
int u = q.front();
++ sz;
q.pop();
// cerr << "? " << u << endl;
for(auto v : G[u]) {
lesser[toid[v]] |= lesser[toid[u]] | (1 << toid[u]);
// cerr << u << " -> " << v << endl;
if(!(-- deg[v])) {
q.push(v);
}
}
}
// cerr << sz << endl;
if(sz != (int)idx[i].size())
return;
for(int j = 0; j < 1 << sz; ++ j) {
state_less[j] = 0;
canplace[j] = (1 << 10) - 1;
for(int k = 0; k < sz; ++ k) {
if(j >> k & 1) {
state_less[j] |= lesser[k];
canplace[j] &= canid[k];
}
}
for(int k = 0; k < 10; ++ k) {
dp[j][k] = 0;
}
}
for(int j = 0; j < 1 << sz; ++ j)
if((state_less[j] & j) == 0)
dp[j][0] = 1;
for(int j = 1; j < 10; ++ j) {
for(int k = 0; k < 1 << sz; ++ k) {
if(dp[k][j - 1]) {
int tmp = (1 << sz) - 1 - k;
for(int st = tmp; ; st = (st - 1) & tmp) {
if(!(canplace[st] >> j & 1))
continue;
if((state_less[st] & (k | st)) == 0) {
// cerr << k << " " << j - 1 << " " << st << " " << endl;
dp[st | k][j] = Add(dp[st | k][j], dp[k][j - 1]);
}
if(!st)
break;
}
}
}
}
mul = Mul(mul, dp[(1 << sz) - 1][9]);
for(auto x : idx[i])
cerr << x << " ";
cerr << endl;
cerr << "Comp: " << dp[(1 << sz) - 1][9] << endl;
}
cerr << "Total = " << mul << endl;
ans = Add(ans, mul);
}
void Solve(int pos, Dsu now, vector<vector<int> > less) {
if(pos == tot) {
Calc(now, less);
return;
}
int len = eq[pos][0].length();
for(int i = 0; i < len; ++ i) {
Dsu nxt = now;
if(isdigit(eq[pos][0][i]) && isdigit(eq[pos][1][i])) {
int l = eq[pos][0][i] - '0', r = eq[pos][1][i] - '0';
if(l > r)
break;
if(l < r)
Solve(pos + 1, nxt, less);
if(eq[pos][0][i] != eq[pos][1][i]) {
break;
}
}
if(isdigit(eq[pos][0][i])) {
int l = eq[pos][0][i] - '0', r = eq[pos][1][i] - 'A';
if(nxt.Set(r, l + 1, 9))
Solve(pos + 1, nxt, less);
if(!now.Set(r, l, l))
break;
continue;
}
if(isdigit(eq[pos][1][i])) {
int l = eq[pos][0][i] - 'A', r = eq[pos][1][i] - '0';
if(nxt.Set(l, 0, r - 1))
Solve(pos + 1, nxt, less);
if(!now.Set(l, r, r))
break;
continue;
}
int l = eq[pos][0][i] - 'A', r = eq[pos][1][i] - 'A';
cerr << eq[pos][0][i] << " < " << eq[pos][1][i] << endl;
less[l].push_back(r);
Solve(pos + 1, nxt, less);
less[l].pop_back();
if(!now.Merge(l, r))
break;
}
}
int main() {
ios :: sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n;
d.Init();
for(int i = 1; i <= n; ++ i) {
cin >> e;
string lef = "", rig = "";
int len = e.length(), pos = -1;
for(int j = 0; j < len; ++ j) {
if(e[j] == '=' || e[j] == '>' || e[j] == '<') {
pos = j;
break;
}
}
for(int j = 0; j < pos; ++ j)
lef += e[j];
for(int j = pos + 1; j < len; ++ j)
rig += e[j];
if(e[pos] == '=') {
while(lef.length() < rig.length())
lef = '0' + lef;
while(rig.length() < lef.length())
rig = '0' + rig;
int l = lef.length();
for(int j = 0; j < l; ++ j) {
if(isdigit(lef[j]) && isdigit(rig[j])) {
if(lef[j] != rig[j]) {
return 0 * puts("0");
}
continue;
}
if(isdigit(lef[j])) {
d.Set(rig[j] - 'A', lef[j] - '0', lef[j] - '0');
continue;
}
if(isdigit(rig[j])) {
d.Set(lef[j] - 'A', rig[j] - '0', rig[j] - '0');
continue;
}
d.Merge(lef[j] - 'A', rig[j] - 'A');
}
continue;
}
if(e[pos] == '>') {
swap(lef, rig);
}
if(rig.length() < lef.length()) {
int diff = lef.length() - rig.length();
for(int j = 0; j < diff; ++ j) {
if(!d.Set(lef[j] - 'A', 0, 0)) {
return 0 * puts("0");
}
}
string tmp = "";
for(int j = diff; j < (int)lef.length(); ++ j) {
tmp += lef[j];
}
lef = tmp;
assert(lef.length() == rig.length());
}
else {
while(lef.length() < rig.length()) {
lef = '0' + lef;
}
}
eq[tot][0] = lef;
eq[tot][1] = rig;
cerr << eq[tot][0] << " < " << eq[tot][1] << endl;
tot ++;
}
Solve(0, d, vector<vector<int> >(26, vector<int>()));
printf("%d\n", ans);
}