#include <iostream>
#include <vector>
#include <set>
#include <unordered_map>
#include <algorithm>
#include <cassert>
namespace boost {template <class T>struct integer_iterator {T a;bool operator != (integer_iterator const & it) const { return a != it.a; }T operator * () const { return a; }integer_iterator & operator ++ () { ++ a; return *this; }integer_iterator operator ++ (int) { return { a ++ }; }};template <class T>struct integer_range {T l, r;typedef integer_iterator<T> iterator;iterator begin() const { return { l }; }iterator end  () const { return { r }; }};template <class T>integer_range<T> irange(T l, T r) { return { l, r }; }template <class T>struct integer_iterator_with_step {T a, d, i;bool operator != (integer_iterator_with_step const & it) const { return a != it.a or d != it.d or i != it.i; }T operator * () const { return a+d*i; }integer_iterator_with_step & operator ++ () { ++ i; return *this; }integer_iterator_with_step operator ++ (int) { return { a, d, i ++ }; }};template <class T>struct strided_integer_range {T l, r, s;typedef integer_iterator_with_step<T> iterator;iterator begin() const { return { l, s, 0 }; }iterator end  () const { return { l, s, (r - l) / s + 1 }; }};template <class T>strided_integer_range<T> irange(T l, T r, T s) { return { l, r, s }; }}
typedef long long ll;
using namespace std;
using namespace boost;
#define endl "\n"
ll to_integer(vector<int> const & t, vector<int> const & xs) {
    ll n = 0;
    for (int x : xs) {
        n = 10*n + t[x];
    }
    return n;
}
bool ok(vector<int> const & t, vector<vector<int> > const & xss) {
    for (auto && xs : xss) {
        if (t[xs[0]] == 0 and xs.size() >= 2) return false;
    }
    int last = 0;
    for (int i : irange<int>(0, xss.size()-1)) {
        last += t[xss[i].back()];
    }
    if (last % 10 != t[xss.back().back()]) return false;
    ll acc = 0;
    for (int i : irange<int>(0, xss.size()-1)) {
        acc += to_integer(t, xss[i]);
    }
    return acc == to_integer(t, xss.back());
}
pair<vector<vector<int> >,int> indexing(vector<string> const & ss) {
    set<char> cs;
    for (auto && s : ss) for (char c : s) cs.insert(c);
    unordered_map<char,int> t;
    for (char c : cs) t.insert(make_pair(c, t.size())); // t[c] = t.size(); causes a bug around order of evaluatoin
    vector<vector<int> > xss;
    for (auto && s : ss) {
        xss.emplace_back();
        for (char c : s) {
            xss.back().push_back(t[c]);
        }
    }
    return make_pair(xss,cs.size());
}
ll permutation(int n, int r) {
    ll acc = 1;
    for (int i : irange(0,r)) acc *= n-i;
    return acc;
}
ll solve(vector<string> const & ss) {
    vector<vector<int> > xss; int n; {
        auto p = indexing(ss);
        xss = p.first;
        n = p.second; // number of different alphabetic characters
    }
    ll result = 0;
    vector<int> table(10); for (int i : irange(0,10)) table[i] = i;
    do {
        if (ok(table, xss)) result += 1;
    } while (next_permutation(table.begin(), table.end()));
    assert (result % permutation(10-n,10-n) == 0);
    return result / permutation(10-n,10-n);
}
int main() {
    ios::sync_with_stdio(false);
    while (true) {
        int n; cin >> n;
        if (n == 0) break;
        vector<string> s(n);
        for (int i : irange(0,n)) cin >> s[i];
        cout << solve(s) << endl;
    }
    return 0;
}

Measured memory_bytes: 1240