#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;

const int MAX_N = 12;
typedef pair<int,char> P;

// 入力
int n;
string s[MAX_N];
// f[c] := 文字 c の係数.
int f[256] = {0};
// m[c] := 文字 c に割り当てた数字 (0-9のどれか, まだ割り当てられていないときは -1 )
int m[256] = {0};
// max_digit := 最大の桁数
int max_digit;
// 登場する文字
vector<char> vc;
// is_head[c] := 文字 c が先頭で数字 0 を割り当てることができない.
bool is_head[256];
// used[i] := 数字 i を使ったかどうか.
bool used[10];
// 解
int ans;
// 上限と下限
int low, high;

void debug_1(){
	for(int i=0 ; i < n ; i++ ){
		cout << s[i];
		if( i == n-1 ){
			cout << endl;
		}else if( i == n-2 ){
			cout << " = ";
		}else{
			cout << " + ";
		}
	}
}

void debug_2(){
	for(char c = 'A' ; c <= 'Z' ; c++ ){
		if( f[c] == 0 ) continue;
		cout << f[c] << c << ", ";
	}
	cout << endl;
	for(int i=0 ; i < vc.size() ; i++ ){
		cout << vc[i];
	}
	cout << endl;
	cout << "[" << low << "," << high << "]" << endl;
}

int pow10(int x){
	int a = 1;
	for(int i=0 ; i < x ; i++ ) a *= 10;
	return a;
}

// 解が明らかに存在しないかどうかチェック.
bool is_answer_exist(){
	int a = s[0].size();
	for(int i=1 ; i < n-1 ; i++ ){
		a = max( a , (int)s[i].size() );
	}
	max_digit = max( a , (int)s[n-1].size() );
	// 右辺の桁数が左辺の最大桁数+2以上 か 右辺の桁数が左辺の桁数より小さいとき解はない.
	if( a+2 <= s[n-1].size() || a > s[n-1].size() ){
		return false;
	}
	return true;
}

void init(){
	// 初期化.
	vc.clear();
	for(int i=0 ; i < 10 ; i++ ){
		used[i] = false;
	}
	for(char c = 'A' ; c <= 'Z' ; c++ ){
		f[c] = 0;
		m[c] = -1;
	}
	int a = s[0].size();
	for(int i=1 ; i < n-1 ; i++ ){
		a = max( a , (int)s[i].size() );
	}
	max_digit = max( a , (int)s[n-1].size() );
	// 文字列を逆にする.
	for(int i=0 ; i < n ; i++ ){
		reverse( s[i].begin() , s[i].end() );
	}
	
	// 各文字の係数をまとめておく.
	int h[256] = {0};
	for(int i=0 ; i < n ; i++ ){
		for(int j=0 ; j < max_digit ; j++ ){
			if( s[i].size() <= j ) continue;
			
			h[ s[i][j] ] = 1;
			if( i == n-1 ){
				f[ s[i][j] ] -= pow10(j);
			}else{
				f[ s[i][j] ] += pow10(j);
			}
		}
	}
	// 登場する文字のチェック.
	for(char c = 'A' ; c <= 'Z' ; c++ ){
		if( h[c] ) vc.push_back( c );
	}
	// 係数の小さい順に文字の並び替え
	vector<P> v;
	for(int i=0 ; i < vc.size() ; i++ ){
		char c = vc[i];
		v.push_back( P(f[c],c) );
	}
	sort(v.begin(),v.end());
	// 上限と下限の計算
	int p=9;
	high = low = 0;
	for(int i=0 ; i < v.size() && v[i].first < 0 ; i++ ){
		high -= v[i].first * p--;
	}
	p=9;
	for(int i=v.size()-1 ; i >= 0 && v[i].first >= 0 ; i-- ){
		low -= v[i].first * p--;
	}
	//debug_2();
	
	// 逆にした文字列を元に戻す.
	for(int i=0 ; i < n ; i++ ){
		reverse( s[i].begin() , s[i].end() );
	}
}

int check(){
	int sum = 0;
	for(char c = 'A' ; c <= 'Z' ; c++ ){
		if( m[c] == -1 ) continue;
		sum += m[c] * f[c];
	}
	return sum;
}

void solve(int pos, int k, int sum ){
	if( pos == k ){
		if( sum == 0 ){
			ans++;
		}
		return ;
	}
	if( sum < low || high < sum ) return;
	
	// c := 今割り当てようとしている文字
	char c = vc[pos];
	for(int i=0 ; i < 10 ; i++ ){
		if( used[i] ) continue;
		if( i == 0 && is_head[c] ) continue;
		
		used[i] = true;
		m[c] = i;
		solve( pos+1 , k , sum + m[c] * f[c] );
		used[i] = false;
		m[c] = -1;
	}
}

int main(){
	while( cin >> n , n ){
		// 初期化
		for(char c = 'A' ; c <= 'Z' ; c++ ) is_head[c] = false;
		// 入力.
		for(int i=0 ; i < n ; i++ ){
			cin >> s[i];
			if( s[i].size() >= 2 ){
				is_head[ s[i][0] ] = true;
			}
		}
		//debug_1();
		
		// 前処理.
		init();
		// 解く.
		ans = 0;
		solve( 0 , vc.size() , 0 );
		// 解を出力.
		cout << ans << endl;
	}
}

Measured memory_bytes: 936