#include <algorithm>
#include <cmath>
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <vector>
#include <cassert>
#include <functional>

using namespace std;

#define LOG(...) printf(__VA_ARGS__)
//#define LOG(...)
#define FOR(i,a,b) for(int i=(int)(a);i<(int)(b);++i)
#define REP(i,n) for(int i=0;i<(int)(n);++i)
#define ALL(a) (a).begin(),(a).end()
#define RALL(a) (a).rbegin(),(a).rend()
#define EXIST(s,e) ((s).find(e)!=(s).end())
#define SORT(c) sort((c).begin(),(c).end())
#define RSORT(c) sort((c).rbegin(),(c).rend())
#define CLR(a) memset((a), 0 ,sizeof(a))

typedef long long ll;
typedef unsigned long long ull;
typedef vector<bool> vb;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<vb> vvb;
typedef vector<vi> vvi;
typedef vector<vll> vvll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;

const int dx[] = { -1, 0, 1, 0 }; const int dy[] = { 0, 1, 0, -1 };

struct UnionFind {
	vector<int> v;
	UnionFind(int n) : v(n) { for (int i = 0; i < n; i++) v[i] = i; }
	int  find(int x) { return v[x] == x ? x : v[x] = find(v[x]); }
	void unite(int x, int y) { v[find(x)] = find(y); }
};
set<char> nzero;
map<char, int> mci;
vector<char> vc;
vector<char> vc2;
int key = 0;
vector<pii> sip;
vector<pii> sia;
void saiki(int idx, int num, bool pre) {
	if (idx == 0) {
		if (pre) {
			sip.push_back({ num, key });
		}
		else {
			sia.push_back({ num, key });
		}
		return;
	}
	vector<char> vcc;
	if (pre)
		vcc = vc;
	else
		vcc = vc2;
	REP(i, 10) {
		if (i == 0 && nzero.find(vcc[vcc.size() - idx]) != nzero.end())
			continue;
		if (!(key&(1 << i))) {
			key |= (1 << i);
			saiki(idx - 1, num + i*mci[vcc[vcc.size() - idx]], pre);
			key &= ~(1 << i);
		}
	}
}

int main() {
	int n;
	while (cin >> n, n) {
		nzero.clear();
		mci.clear();
		vc.clear();
		key = 0;
		sip.clear();
		sia.clear();
		vector<string> s(n);
		REP(i, n) {
			cin >> s[i];
			if (s[i].length() != 1)
				nzero.insert(s[i][0]);
			REP(j, s[i].length()) {
				vc.push_back(s[i][j]);
				if (mci.find(s[i][j]) == mci.end()) {
					mci[s[i][j]] = 0;
				}
				if (i != n - 1) {
					mci[s[i][j]] += (int)pow(10, s[i].length() - j - 1);
				}
				else {
					mci[s[i][j]] -= (int)pow(10, s[i].length() - j - 1);
				}
			}
		}
		/*
		vi nums;
		for (auto x : mci) {
			nums.push_back(x.second);
		}
		SORT(nums);
		REP(i, nums.size()) {
			if (nums[i] > 0) {
				reverse(nums.begin() + i, nums.end());
				break;
			}
		}
		*/
		SORT(vc);
		vc.erase(std::unique(vc.begin(), vc.end()), vc.end());
		/*
		vector<char> vc2;
		REP(i, mci.size()) {
			REP(j, vc.size()) {
				if (nums[i] == mci[vc[j]]) {
					vc2.push_back(vc[j]);
					vc.erase(vc.begin()+j);
				}
			}
		}
		vc = vc2;
		*/
		vc2 = vc;
		vc.erase(vc.begin() + vc.size() / 2, vc.end());
		vc2.erase(vc2.begin(), vc2.begin() + vc2.size() / 2);
		saiki(vc.size(), 0, true);
		saiki(vc2.size(), 0, false);
		SORT(sip);
		RSORT(sia);
		int ans = 0;
		int right = 0;
		REP(i, sip.size())
			FOR(j,right, sia.size())
			if (sip[i].first + sia[j].first == 0) {
				if ((sip[i].second&sia[j].second) == 0)
					ans++;
			}
			else if (sip[i].first + sia[j].first< 0){
				break;
			}
			else {
				right = j;
			}

		cout << ans << endl;
	}
}

Measured memory_bytes: 3820