#include <iostream>
#include <string>

using namespace std;

/* Maximum possible size of grid in columns */
#define MAXCOLS 50

/* Maximum possible size of grid in rows */
#define MAXROWS 50

/* Maximum possible number of species */
#define MAXSPECIES 26

/* Maximum number of neighbors any cell can have */
#define MAXNEIGHBOR 9

/*
 * Defines all possible directions aronud a cell where neighbors could be
 * located. The directions are defined in the form of { row_offset, col_offset }
 */
int dir[][2] = {
    { 0, 1 }, { 0, -1}, { 1, 0 }, { -1, 0 },
    { 1, 1 }, { 1, -1}, { -1, 1 }, { -1, -1 }
};

/*
 * Since the state for a cell depends only on the state from the previous turn,
 * two boards are needed to keep state. One board is checked to see if a cell
 * lives or dies, and the second board is updated with the results for next
 * turn.
 */
char board0[MAXROWS][MAXCOLS];
char board1[MAXROWS][MAXCOLS];

/*
 * To avoid having to copy data back and forth between the two boards, the
 * "current" points points to the board being checked against the rules, and
 * the "next" points to the board being updated with the results of the rules.
 * After each turn, the two pointers are simply swapped.
 */
char (*current)[MAXCOLS] = board0;
char (*next)[MAXCOLS] = board1;

/*
 * These two arrays keep track of the survival and birth rules. For each
 * species,  eight separate booleans keep track if that number of neighbors
 * causes a new cell to be born or the current cell to survive.
 */
bool born[MAXSPECIES][MAXNEIGHBOR];
bool survive[MAXSPECIES][MAXNEIGHBOR];

/* Board size, num species, and num turns for the current simulation */
int rows_num, cols_num, species_num;

/* For each species, keep track of the maximum and minimum number of cells */
int max_count[MAXSPECIES];
int min_count[MAXSPECIES];

/* Initialize board layout from the input */
void parse_board(void)
{
    int row, col;
    
    /* Iterate over all rows and columns */
    for(row = 0; row < rows_num; row++) {
        for(col = 0; col < cols_num; col++) {
            char c;
            
            /* Parse the next input character */
            cin >> c;
            
            /* A period denotes an empty space */
            if(c == '.') {
                current[row][col] = 0;
            }
            
            /* Otherwise, a capital letter specifies the species */
            else {            
                /* Verify the species is valid */
                if(c < 'A' || c > ('A' + species_num - 1))
                    throw "Invalid species";

                /* Assign species to the board */
                current[row][col] = c;
            }                
        }
    }
}

/* Initialize rule arrays from input */
void parse_rules(void)
{
    int species;
    
    /* Process the ruleset for each species */
    for(species = 0; species < species_num; species++) {
        string line;
        int rule, i;
    
        /* Reset the rulset for this species */
        for(rule = 0; rule < MAXNEIGHBOR; rule++) {
            born[species][rule] = false;
            survive[species][rule] = false;
        }

        /* Read the entire ruleset line */
        cin >> line;

        /* Begin with processing survival rules first */
        bool *ruleset = survive[species];
                
        /* Iterate over all characters in the string */
        for(i = 0; i < line.size(); i++) {
            char c = line[i];
        
            /* If a "/" character is encountered, switch to birth ruleset */
            if(c == '/') {
                ruleset = born[species];
            }
            
            /* Otherwise, character specifies the neighbor count */
            else {
            
                /* Verify the input is valid */
                if(c < '0' || c > '8')
                    throw "Invalid character in rule";
                    
                /* Check the same neighbor number is not used twice */
                if(ruleset[c - '0'])
                    throw "Duplicate neighbor number in rule" + line;
                    
                /* Assign to ruleset array */
                ruleset[c - '0'] = true;
            }
        }
    }
}

/* Count the number of cells present of a particular species in current board */
int count_species(int species)
{
    int row, col, total = 0;
    
    for(row = 0; row < rows_num; row++) {
        for(col = 0; col < cols_num; col++) {        
            if(current[row][col] == species + 'A')
                total++;
        }
    }
    
    return total;
}

/* Return number of living cells of "species" adjacent to (cur_row, cur_col) */
int adjacent(int cur_row, int cur_col, int species)
{
    int i, total = 0;
    
    /* Iterate over all possible adjacent directions */
    for(i = 0; i < MAXNEIGHBOR; i++) {
        
        /* Calculate new indicies */
        int row = cur_row + dir[i][0];
        int col = cur_col + dir[i][1];
        
        /* If adjacent position is out of bounds, ignore it */
        if(row < 0 || row >= rows_num || col < 0 || col >= cols_num)
            continue;
            
        /* If adjacent position has a cell of the right species, count it */
        if(current[row][col] == species + 'A')
            total++;
    }
    
    return total;
}

/* Perform one turn of the actual simulation */
void simulate(void)
{
    int row, col, species;

    /* Iterate over all rows and columns */
    for(row = 0; row < rows_num; row++) {
        for(col = 0; col < cols_num; col++) {
        
            /* Assume cell in next turn will not survive */
            next[row][col] = 0;
            
            /* Check the rules for each species type */
            for(species = 0; species < species_num; species++) {
                bool *ruleset;
                int num;
                            
                /* Use ruleset appropriate to cell surviving or being born */
                if(current[row][col] == species + 'A')
                    ruleset = survive[species];
                else
                    ruleset = born[species];
                    
                /* Count the number of cells adjacent to this one */
                num = adjacent(row, col, species);

                /* If cell lives, do not try other species */
                if(ruleset[num]) {
                    next[row][col] = species + 'A';
                    break;
                }                
            }
        }
    }

    /* Swap pointers in preparation for next simulation turn */
    char (*temp)[MAXCOLS] = current;
    current = next;
    next = temp;
    
    /* Update counts for each species */
    for(species = 0; species < species_num; species++) {
        int num = count_species(species);
        
        if(num > max_count[species])
            max_count[species] = num;
        if(num < min_count[species])
            min_count[species] = num;
    }
}

#ifdef DEBUG
/* Bring out the current board state for debugging purposes */
void print_board(void)
{
    int row, col;

    /* Iterate over all rows and columns */
    for(row = 0; row < rows_num; row++) {
        for(col = 0; col < cols_num; col++) {
        
            /* Print a cell if it is present, or print period for empty spaces */
            if(current[row][col])
                cout << current[row][col];
            else
                cout << ".";
        }
        cout << endl;
    }
}
#endif

/* Main body of program */
void process(void)
{
    int sim_num, sim_idx;
    
    /* Throw exceptions on unexpected EOF */
    cin.exceptions(ios::eofbit);
       
    /* Read how many boards are to be analyzed */
    cin >> sim_num;

    /* Process each board separately */
    for(sim_idx = 0; sim_idx < sim_num; sim_idx++) {
        int i, turns;

        /* Parse the board size and number of species */
        cin >> cols_num >> rows_num >> species_num;
        
        /* Verify all numbers are within their limits */
        if(cols_num < 0 || cols_num > MAXCOLS)
            throw "Invalid X size";
        if(rows_num < 0 || rows_num > MAXROWS)
            throw "Invalid Y size";
        if(species_num < 0 || species_num > MAXSPECIES)
            throw "Invalid number of species";

        /* Initialize board layout and ruleset from input */
        parse_board();
        parse_rules();

        /* Initialize min/max counts for all species */
        for(i = 0; i < species_num; i++) {
            max_count[i] = count_species(i);
            min_count[i] = count_species(i);
        }

#ifdef DEBUG
        /* Print out iniital board state */
        cout << "Initial state:" << endl;
        print_board();
#endif
        
        /* Read in total number of turns to simulate */
        cin >> turns;        
        
        /* Run the simulation */
        cout << "Simulation #" << sim_idx + 1 << endl;
        for(i = 0; i < turns; i++) {
            simulate();
            
#ifdef DEBUG
            cout << "State after turn #" << i + 1 << endl;
            print_board();
#endif
        }        
        
        /* Prinout out the results after all simulations */
        for(i = 0; i < species_num; i++) {
            cout << "Species " << (char) (i + 'A') << ": ";
            cout << "At most " << max_count[i] << " live, ";
            cout << "at least " << min_count[i] << " live." << endl;
        }
    }    
}

/* Run program and print out any exceptions that occur */
int main(void)
{
    /* Run main body of code */
    try {
        process();
    }
    
    /* Catch any internally generated exceptions */
    catch(char const *e) {
        cerr << "Exception: " << e << endl;
    }
    
    /* Catch any internally generated exceptions */
    catch(string &e) {
        cerr << "Exception: " << e << endl;
    }
    
    /* Catch unexpected EOF on input */
    catch(ios::failure const &ee) {
        cerr << "Exception: Unexpected EOF on input" << endl;
    }
    
    return 0;
}