// Solution to "ACronym Maker" by Bob Roos
//
// Input abbreviation, abbrev, and phrase, ignoring insignificant words.
// Search for substrings of abbrev in each of the words phrase[0],
// ..., phrase[numWords-1], then combine results to get number of ways
// to form the abbreviation.

import java.io.*;
import java.util.*;

public class ACM {

 // input-related stuff:
 public static BufferedReader in;
 public static StringTokenizer tok;

 public static String insig[]; // array of insignificant words
 public static String phrase[]; // array of significant words
 public static int numWords; // number of significant words
 public static String abbrev; // the abbreviation
 public static Hashtable lookup; // used to memoize search for substrings

 // "main" contains basic input/process/output loop:
 public static void main(String[] args) throws IOException {
   in = new BufferedReader(new InputStreamReader(System.in));

   // Now process the various test cases:
   String line;
   while (!(line = in.readLine().trim()).equals("0")) {
     // Read in the insignificant words:
     int n = Integer.parseInt(line);

     insig = new String[n];
     tok = new StringTokenizer("");
     for (int i = 0; i < n; i++) {
       insig[i] = nextWord();
     }
     while (!(line = in.readLine().trim()).equals("LAST CASE")) {
       tok = new StringTokenizer(line);

      // First item on each line is the abbreviation:
       abbrev = tok.nextToken();

      // Next k items are the words of the phrase:
       numWords = 0;
       int k = tok.countTokens();
       phrase = new String[k];

      // Read in phrase, but only save the significant words:
       for (int i = 0; i < k; i++) {
         String word = tok.nextToken();
         boolean ins = false;

         // Linear search for insignificant words:
         for (int j = 0; j < n; j++)
           if (insig[j].equals(word)) {
             ins = true;
             break;
           }

         // Save the word if it is significant:
         if (!ins)
           phrase[numWords++] = word;
       }

       process(); // Solve this test case
     }
   }
 }


 // Process a single test case:
 public static void process() {

// DEBUG:
//  System.out.print(abbrev = " ");
//  for (int i = 0; i < numWords; i++)
//    System.out.print(phrase[i] + " ");
//  System.out.println();
//

   int k = abbrev.length();
   abbrev = abbrev.toLowerCase();

   // Easy base case -- too many words:
   if (numWords > k) {
     System.out.println(abbrev.toUpperCase() + " is not a valid abbreviation");
     return;
   }

   // "lookup" stores pairs (u,v) of strings and the number of ways that
   // u is a substring of v:
   lookup = new Hashtable();

   int numAbbr = 0; // number of ways to abbreviate

   // Another base case -- exactly one letter in the abbreviation:
   if (k == 1) {

     // There must be at least one word in the phrase, and previous
     // tests guarantee exactly one:
     numAbbr = occurs(abbrev,0,k-1,phrase[0],0,phrase[0].length()-1);
     if (numAbbr == 0)
       System.out.println(abbrev.toUpperCase() + " is not a valid abbreviation");
     else
       System.out.println(abbrev.toUpperCase() + " can be formed in " + numAbbr + " ways");
     return;
   }

   // Another base case -- exactly one word in the phrase:
   if (numWords == 1) {
     numAbbr = occurs(abbrev,0,k-1,phrase[0],0,phrase[0].length()-1);
     if (numAbbr == 0)
       System.out.println(abbrev.toUpperCase() + " is not a valid abbreviation");
     else
       System.out.println(abbrev.toUpperCase() + " can be formed in " + numAbbr + " ways");
     return;
   }

   // General case:
   int first[] = new int[k-numWords+1]; // counts prefixes of abbrev in first
                                        // word of the phrase
   int last[] = new int[k-numWords+1]; // counts suffixes of abbrev occurring
                                       // in last word of the phrase

   // counts internal substrings of abbrev occurring in all but the first
   // and last words: inter[i][j][l] is number of occurrences of a
   // particular substring of abbrev of length l-j+1 in the (i+1)st word
   // of the phrase:
   int inter[][][] = new int[numWords-2][k-numWords+1][k-numWords+1];

   for (int i = 0; i < k-numWords+1; i++)
     first[i] = occurs(abbrev,0,i,phrase[0],0,phrase[0].length()-1);

// DEBUG:
//  for (int i = 0; i < k-numWords+1; i++)
//    System.out.println(abbrev.substring(0,i+1) + " occurs in " +
//                       phrase[0] + " " + first[i] + " times.");

   for (int i = 0; i < k-numWords+1; i++)
     last[i] = occurs(abbrev,numWords+i-1,k-1,phrase[numWords-1],0,
                      phrase[numWords-1].length()-1);

// DEBUG:
//  for (int i = 0; i < k-numWords+1; i++)
//    System.out.println(abbrev.substring(numWords+i-1,k) + " occurs in "
//                       + phrase[numWords-1] + " " + last[i] + " times.");

   for (int i = 0; i < numWords-2; i++) {
     for(int j = 0; j < k-numWords+1; j++) {
       for(int l = j; l < k-numWords+1; l++) {
         inter[i][j][l] = occurs(abbrev,i+j+1,i+l+1,
                                 phrase[i+1],0,phrase[i+1].length()-1);
       }
     }
   }

// DEBUG:
//  for (int i = 0; i < numWords-2; i++) {
//    System.out.println(phrase[i+1]+":");
//    for(int j = 0; j < k-numWords+1; j++) {
//      for (int l = 0; l < j; l++)
//         System.out.print("\t");
//
//      for(int l = j; l < k-numWords+1; l++) {
//         System.out.print(inter[i][j][l]+"\t");
//      }
//      System.out.println();
//    }
//  }

   // Now put it all together using matrix multiplication:
   int temp[] = new int[k-numWords+1];

   // Save current vector:
   for (int i = 0; i < k-numWords+1; i++)
     temp[i] = first[i];

   for (int i = 0; i < numWords-2; i++) {
      for (int j = 0; j < k-numWords+1; j++) {
        // Overwrite current vector with result of multiplication:
        first[j] = 0;
        for (int l = 0; l <= j; l++) {
          first[j] += temp[l] * inter[i][l][j];
        }
      }

      // Save current vector:
      for (int j = 0; j < k-numWords+1; j++)
        temp[j] = first[j];
   }

   // Final step: multiply by the vector containing number of suffixes:
   for (int i = 0; i < k-numWords+1; i++)
     numAbbr += first[i] * last[i];

   if (numAbbr == 0)
     System.out.println(abbrev.toUpperCase() + " is not a valid abbreviation");
   else
     System.out.println(abbrev.toUpperCase() + " can be formed in " +
                        numAbbr + " ways");
 }

 // Get the next insignificant word from the input:
 public static String nextWord() throws IOException {

   while (!tok.hasMoreTokens()) {
     tok = new StringTokenizer(in.readLine());
   }
   return tok.nextToken();
 }

 // Search for all occurrences of w[i] w[i+1] ... w[j] inside
 // x[k] x[k+1] ... x[l]:

 public static int occurs(String w, int i, int j,
                          String x, int k, int l) {
   // Easy base case: first string is empty
   if (j < i)
     return 1;

   // Easy base case: second string is too short to hold first string:
   if (l-k < j-i)
      return 0;

   // Prepare to look up in table:
   String a = w.substring(i,j+1);
   String b = x.substring(k,l+1);
   Integer temp = (Integer)(lookup.get(a+","+b));

   // Found it -- we've already searched for this string:
   if (temp != null) {
      return temp.intValue();
   }

   // Didn't find it, so match first letters and use recursion:
   int count = 0;
   for (int r = k; r <= l; r++)
      if (w.charAt(i) == x.charAt(r)) {
        int t = occurs(w,i+1,j,x,r+1,l);
        count += t;
      }
   a = w.substring(i,j+1);
   b = x.substring(k,l+1);

   // Save in table for future lookups:
   lookup.put(a+","+b,new Integer(count));
   return count;
 }
}



