/* Import the Java I/O package */
import java.io.*;
import AppletConsoleApp;

/**
 * Solution to the 1998 British Informatics Olympiad exam
 * question 3: Alphametics
 *
 * Reads 3 to 6 lines of up to 6 characters each forming a sum (with
 * the last line as the total); each character represents a different
 * digit.  Let there be N lines and M characters.  Write the nth line
 * as Wn1 * X1 + ... + WnM * XM where Xm is the value assigned to
 * character m.  The solution is therefore to find appropriate X1..XM
 * satisfying W1 * X1 + ... + WM * XM = 0, where
 * Wm = W1m + W(N-1)m - WNm.  Solution vectors lie in the M-1
 * dimensional space that is orthogonal to W; additionally, if all
 * elements of a solution are less than or equal to 4, it can be
 * doubled, or if less than or equal to 3, it can also be tripled,
 * if less than or equal to 2, quadrupled.
 *
 * This representation is fast enough for exhaustive search of all
 * 10! combinations.
 *
 * This application that can be run either from the console
 * as a stand-alone application or from an in-applet
 * console created with the AppletConsole applet.
 *
 * Solution copyright (c) 1998 The British Informatics Olympiad (BIO).
 *
 * This program may be freely copied by persons or organisations
 * involved in the British Informatics Olympiad or the International
 * Olympiad in Informatics, on condition that no changes are made and
 * this notice is not altered. Distribution for profit is forbidden
 * unless permission is first obtained in writing from the BIO.
 *
 * This program is for educational purposes only and comes with no
 * warranty, implied or otherwise, as to its fitness for any purpose.
 *
 * Author:   Antony Rix
 * Internet: http://www.christs.cam.ac.uk/bio/
 * E-mail:   a.rix@lineone.net
 * S-mail:   The British Informatics Olympiad
 *           Christ's College
 *           Cambridge CB2 3BU
 *           United Kingdom
 *
 * @author  Antony Rix
 * @version 0.1
 * @see     AppletConsoleApp
 * @see     AppletConsole
 */
class BIO98R1Q3App extends AppletConsoleApp {
  /**
   * Start the application from the command line.
   */
  public static void main(String[] args) {
	  BIO98R1Q3App thisApp = new BIO98R1Q3App();
	  thisApp.redirectStreams(System.in, System.out);
	  thisApp.run();
	}

  /**
   * Data structure to store the lines to be summed
   */
  char[][] alphametic = new char[6][10];

  /**
   *  Number of lines
   */
  int N;

  /**
   *  Number of characters
   */
  int M;

  /**
   * Characters in the alphametic.
   */
  String Letters;
  
  /**
   * Weights of solution equation (use long as its accuracy,
   * 64 bits, is higher than int).
   */
  long[] W = new long[10];

  /**
   * Solution.
   */
  long[] X = new long[10];

  /**
   * Whether a specific digit has been allocated
   */
  boolean[] allocDigit = new boolean[10];

  /**
   * Number of solutions found
   */
  int S;

  /**
   * Number of valid combinations (for 3(d))
   */
  int P;
  
  /**
   * The implementation of this application.
   */
	public void run() {
    int i, j, L;
    
    try {
      out.println( "BIO'98 Question 3" );
  	  /* Create a StreamTokenizer to allow us to read in the two numbers */
  	  StreamTokenizer sin = new StreamTokenizer( in );

  	  /* Read in initial co-ordinates */
      out.print( "Number of lines:" );
	    sin.nextToken();
	    N = (int)sin.nval;
	    if( (N > 6) || (N < 3) ) {
	      if( N == -1 ) {
	        out.println( "Solution to 3(d)" );
	        try3d();
	      } else out.println( "Expected between 3 and 6 lines" );
	    } else {
  	    for( i = 0; i < N; i++ ) {
	        out.print( "Line " + (i+1) + ":" );
  	      sin.nextToken();
  	      for( j = 0; j < 10; j++ ) alphametic[i][j] = ' ';
  	      L = sin.sval.length();
    	    for( j = 1; j <= L; j++ )
    	      alphametic[i][L-j] = sin.sval.charAt( j - 1 );
	      }

        /* Compute solutions */
  	    tryMatch();
  	    if( S == 0 ) out.println( "Impossible" );
  	    if( S == 1 ) out.println( "Unique" );
  	  }
  	} catch (IOException e) { out.println("I/O failure"); };
	  out.println( "Program finished." );
	}

	/**
	 * Solution of the alphametic.  tryMatch() first converts
	 * alphametic[] to the weights form, then generates all
	 * permutations of X and trys them for a solution.
	 * Finally, solutions are verified using checkSolution()
	 * which discards those with leading zeros and displays
	 * and counts the rest.
	 */
	void tryMatch() {
	  int p, i, j, m;
	  long Sum, digit;
	  char c;

    /* Initialise the data */
    for( j = 0; j < 10; j++ ) {
      W[j] = 0L;
      X[j] = 0L;
      allocDigit[j] = false;
    }
    S = 0;
    Letters = "";
    M = 0;

    /* Find the different letters in the alphametic and their weights */
    for( i = 0; i < N; i++ ) {
      digit = 1L;
      for( j = 0; j < 10; j++ ) {
        c = alphametic[i][j];
        if( c != ' ' ) {
          m = Letters.indexOf( c );
          if( m < 0 ) {
            Letters = Letters + c;
            m = M;
            M++;
          }
          if( i < (N-1) ) W[m] += digit; else W[m] -= digit;
        }
        digit *= 10L;
      }
    }

    /* Generate possible solutions */
	  X[0] = 0;
	  Sum = 0L;
	  p = 0;
	  while( X[0] < 10 ) {
	    if( p == M ) {
	      if( Sum == 0L ) checkSolution();
	      p--;
	      allocDigit[(int)X[p]] = false;
	      Sum -= X[p] * W[p];
	      X[p]++;
	    }
      if( X[p] >= 10 ) {
        p--;
        if( p >= 0 ) {
  	      allocDigit[(int)X[p]] = false;
  	      Sum -= X[p] * W[p];
          X[p]++;
        }
        continue;
      }
      if( !allocDigit[(int)X[p]] ) {
        allocDigit[(int)X[p]] = true;
        Sum += X[p] * W[p];
        p++;
        if(p < M ) X[p] = 0;
      }
      else X[p]++;
	  }
	}

	/**
	 * Check a candidate solution
	 */
	void checkSolution() {
	  String answer = "";
	  int i, j;
	  for( i = 0; i < N; i++ ) {
	    if( i == 0 ) answer = " ";
	    else if( i < (N-1) ) answer = answer + " + ";
	    else answer = answer + " = ";
	    for( j = 9; j >= 0; j-- ) if( alphametic[i][j] != ' ' )
	      answer = answer +
	        ((char)(X[Letters.indexOf(alphametic[i][j])]+48L));
	  }
	  if( answer.indexOf( " 0" ) < 0 ) {
	    /* This is a valid solution */
	    out.println( answer );
	    S++;
	  }
	}

  /**
   * Solution to 3(d): ABC + DEA = X where X contains only
   * the letters A to E and forms a valid sum.
   * (i) How many letter combinations for X result in solutions?
   * (ii) How many different sums are represented?
   * For (i), there can be no more than 5^4 + 5*3 = 750
   * valid combinations (in fact there will be rather less);
   * we pre-compute the 750 candidate combinations
   */
	void try3d() {
	  long[][] Ws = new long[5][750];
	  int[] leftMostLetter = new int[750];
	  String[] solutions = new String[750];
	  boolean[] isValid = new boolean[750];
	  boolean solved;
	  int i, j, k, l, p, count, validCombinations, differentSums;
	  long Sum;
	  
	  Letters = "ABCDE";
	  M = 5;
	  /* Weights for ABC + DEA for these Letters */
	  W[0] = 101L;
	  W[1] = 10L;
	  W[2] = 1L;
	  W[3] = 100L;
	  W[4] = 10L;

	  /* Generate actual weights for each candidate combination */
	  for( i = 0; i < 10; i++ ) allocDigit[i] = false;
	  count = 0;
	  for( i = 0; i < M; i++ )
	    for( j = 0; j < M; j++ )
	      for( k = 0; k < M; k++ )
	        for( l = 0; l < M; l++ ) {
    	      /* i,j,k,l contains a permutation of 4 letters A to E */
    	      solutions[count] = "" +
    	        Letters.charAt( i ) + 
    	        Letters.charAt( j ) + 
    	        Letters.charAt( k ) + 
    	        Letters.charAt( l );
    	      leftMostLetter[ count ] = i;
    	      for( p = 0; p < M; p++ ) Ws[p][count] = W[p];
    	      Ws[i][count] -= 1000L;
    	      Ws[j][count] -= 100L;
    	      Ws[k][count] -= 10L;
    	      Ws[l][count] -= 1L;
    	      count++;
	        }
	  for( i = 0; i < M; i++ )
	    for( j = 0; j < M; j++ )
	      for( k = 0; k < M; k++ ) {
  	      /* i,j,k contains a permutation of 3 letters A to E */
  	      solutions[count] = "" +
  	        Letters.charAt( i ) + 
  	        Letters.charAt( j ) + 
  	        Letters.charAt( k );
  	      leftMostLetter[ count ] = i;
  	      for( p = 0; p < M; p++ ) Ws[p][count] = W[p];
  	      Ws[i][count] -= 100L;
  	      Ws[j][count] -= 10L;
  	      Ws[k][count] -= 1L;
  	      count++;
        }

    /* Investigate if the permutations solve the problem */
    validCombinations = 0;
    differentSums = 0;
    for( i = 0; i < count; i++ ) isValid[i] = false;
    for( j = 0; j < M; j++ ) {
      X[j] = 0L;
      allocDigit[j] = false;
    }

    /* Generate possible solutions */
	  X[0] = 0;
	  p = 0;
	  while( X[0] < 10 ) {
	    if( p == M ) {
	      /* Check if X contains a solution */
	      solved = false;
	      for( k = 0; k < count; k++ ) {
	        Sum = 0L;
  	      for( i = 0; i < M; i++ ) Sum += Ws[i][k] * X[i];
  	      if( (Sum == 0L) && (X[0] != 0L) && (X[3] != 0L) &&
  	          (X[leftMostLetter[k]] != 0L) ) {
  	        solved = true;
  	        isValid[k] = true;
  	        out.print( "ABC + DEA = " + solutions[k] );
  	        if( solutions[k].length() > 3 )
  	          out.print( " => " );
  	        else
  	          out.print( "  => " );
  	        out.print( X[0] );
            out.print( X[1] );
  	        out.print( X[2] + " + " + X[3] );
  	        out.print( X[4] );
  	        out.print( X[0] + " = " );
  	        out.print( X[(char)solutions[k].charAt( 0 ) - 65] );
  	        out.print( X[(char)solutions[k].charAt( 1 ) - 65] );
  	        out.print( X[(char)solutions[k].charAt( 2 ) - 65] );
  	        if( solutions[k].length() > 3 )
    	        out.println( X[(char)solutions[k].charAt( 3 ) - 65] );
    	      else
      	      out.println( " " );
  	      }
  	    }
  	    if( solved ) differentSums++;
	      p--;
	      allocDigit[(int)X[p]] = false;
	      X[p]++;
	    }
      if( X[p] >= 10 ) {
        p--;
        if( p >= 0 ) {
  	      allocDigit[(int)X[p]] = false;
          X[p]++;
        }
        continue;
      }
      if( !allocDigit[(int)X[p]] ) {
        allocDigit[(int)X[p]] = true;
        p++;
        if(p < M ) X[p] = 0;
      }
      else X[p]++;
	  }

    for( k = 0; k < count; k++ ) if( isValid[k] ) validCombinations++;
    out.println( validCombinations );
    out.println( differentSums );
	}
}
