#include <algorithm>
#include <iostream>
#include <set>
#include <vector>
//backtracking algorithm was taken from here:
//http://e...content-available-to-author-only...a.org/wiki/Backtracking
std::vector<int> digitsFromInt(int num)
{
if(num == 0)
{
return std::vector<int>(1, 0);
}
std::vector<int> ret;
while(num != 0)
{
ret.push_back(num % 10);
num /= 10;
}
std::reverse(ret.begin(), ret.end());
return ret;
}
template <typename T>
class Backtrack
{
protected:
virtual T root(T) = 0;
virtual bool reject(T, T) = 0;
virtual bool accept(T, T) = 0;
virtual T first(T, T) = 0;
virtual T next(T, T) = 0;
virtual void output(T, T) = 0;
private:
T P;
void bt(T c)
{
if(reject(P, c))
{
return;
}
if(accept(P, c))
{
output(P, c);
}
T s = first(P, c);
while(s.size() != 0)
{
bt(s);
s = next(P, s);
}
}
public:
void backtrack(T p)
{
bt(root(this->P = p));
}
};
class Crypt : public Backtrack< std::vector<int> >
{
private:
int count;
public:
Crypt() : Backtrack< std::vector<int> >()
{
count = 0;
}
std::vector<int> root(std::vector<int> P)
{
//return the empty set
return std::vector<int>(0);
}
bool reject(std::vector<int> P, std::vector<int> c)
{
//we can only reject combinations that are larger than 5
//combinations less than 5 still need to be expanded
return (c.size() > 5);
}
bool accept(std::vector<int> P, std::vector<int> c)
{
/** The following cryptarithm is a multiplication problem that can be solved by
* substituting digits from a specified set of N digits into the positions marked with *.
* If the set of prime digits {2,3,5,7} is selected, the cryptarithm is called a PRIME CRYPTARITHM.
*
* * * *
* x * *
* -------
* * * * <-- partial product 1
* * * * <-- partial product 2
* -------
* * * * *
*
* Digits can appear only in places marked by `*'. Of course, leading zeroes are not allowed.
* Note that the 'partial products' are as taught in USA schools. The first partial product is
* the product of the final digit of the second number and the top number. The second partial
* product is the product of the first digit of the second number and the top number.
*/
//the partial candidate c must have at least 5 elements to even be able to perform the multiplication
if(c.size() < 5)
{
return false;
}
//the partial candidate has to result in a multiplication that consists of only digits from parameter P
int num1 = P[c[0]] * 100 + P[c[1]] * 10 + P[c[2]];
int num2 = P[c[3]] * 10 + P[c[4]];
int part1 = P[c[4]] * num1;
int part2 = P[c[3]] * num1;
int ans = num1 * num2;
// std::cerr << num1 << " * " << num2 << " = " << ans << std::endl;
// std::cerr << part1 << " " << part2 << std::endl;
//convert all numbers to digit lists
std::vector<int> dPart1 = digitsFromInt(part1);
std::vector<int> dPart2 = digitsFromInt(part2);
std::vector<int> dAns = digitsFromInt(ans);
//part1 and part2 must be three digits
//ans must be four digits
if(dPart1.size() != 3 || dPart2.size() != 3 || dAns.size() != 4)
{
return false;
}
//combine all the digit lists into one
std::vector<int> digits(3 + 3 + 4);
auto it = std::copy(dPart1.begin(), dPart1.end(), digits.begin());
it = std::copy(dPart2.begin(), dPart2.end(), it);
std::copy(dAns.begin(), dAns.end(), it);
//then check to see that the digits in the set are all members of P
for(int digit : digits)
{
// std::cerr << digit << ", ";
if(std::find(P.begin(), P.end(), digit) == P.end())
{
//a digit was found that was not in P
return false;
}
}
// std::cerr << std::endl;
//all digits were in P, so the solution is acceptable
return true;
}
std::vector<int> first(std::vector<int> P, std::vector<int> c)
{
if(c.size() < 5)
{
c.push_back(0);
return c;
}
return std::vector<int>(0);
}
std::vector<int> next(std::vector<int> P, std::vector<int> s)
{
if(s.size() != 5)
{
return std::vector<int>(0);
}
bool carry = false;
int max = P.size();
for(auto it = s.rbegin(); it != s.rend(); it++)
{
(*it) += 1;
carry = (*it >= max);
(*it) %= max;
if(!carry)
{
break;
}
}
if(carry)
{
return std::vector<int>(0);
}
return s;
}
void output(std::vector<int> P, std::vector<int> c)
{
count++;
}
int getCount()
{
return count;
}
};
int main(int argc, char* argv[])
{
try
{
int data_size;
//continuously request input for size of the set, until size of set is zero or less
while(std::cin >> data_size && data_size > 0)
{
//request inputs for members of the set
std::vector<int> numbers(data_size, 0);
for (int i = 0; i < data_size; i++)
{
std::cin >> numbers[i];
}
//since the numbers can be given out of order they must be sorted
std::sort(numbers.begin(), numbers.end());
// for(int num : numbers)
// {
// std::cerr << num << ", ";
// }
// std::cerr << std::endl;
Crypt crypt;
crypt.backtrack(numbers);
std::cout << crypt.getCount() << std::endl;
}
}
catch(...)
{
std::cerr << "there was a problem" << std::endl;
}
return 0;
}