import java.io.File;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.Scanner;

class ProblemB {
	static Scanner scanner;
	static char[] alphabet;
	static double[][] errorProbMatrix;
	static double[][] transitionProbMatrix; 
	static String[] strings;
	
	final static double EPSILON = 1e-8;
		
	public static void main(String[] args) {
//                Locale.setDefault( Locale.ENGLISH );
                if( args.length > 0 )
                    processInput(args[0]);
                else
                    processInput(null);
	}
	
	public static void processInput( String a ){
		File inputFile;
		        if( a == null )
		            inputFile = new File("b.in");
		        else
		            inputFile = new File(a);
		try {
			scanner = new Scanner(System.in);
//			scanner.useLocale(java.util.Locale.US);
			
			int testCaseCount = scanner.nextInt();
			for( int i = 0; i < testCaseCount; i++ ) {
				processTestCase();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static void processTestCase(){
		int characterCount = scanner.nextInt();
		alphabet = new char[characterCount];
		errorProbMatrix = new double[characterCount][characterCount];
		transitionProbMatrix = new double[characterCount][characterCount];
		                
		for( int i = 0; i < characterCount; i++ ){
			String nextToken = scanner.next();
			alphabet[i] = nextToken.charAt(0);
		}
		
		// log( a * b ) = log( a ) + log( b )
		// so log( p_err * p_trans ) = log( p_err ) + log( p_trans ) etc
		// summing with logs should enable higher resolution
		
		for( int i = 0; i < characterCount; i++ ){
			for( int j = 0; j < characterCount; j++){
				double currentProbability = scanner.nextDouble();
				errorProbMatrix[i][j] = Math.log(currentProbability);
			}
		}
		
		for( int i = 0; i < characterCount; i++ ){
			for( int j = 0; j < characterCount; j++){
				double currentProbability = scanner.nextDouble();
				transitionProbMatrix[i][j] = Math.log(currentProbability);
			}
		}
		
		int stringCount = scanner.nextInt();
		strings = new String[stringCount];
		for( int i = 0; i < stringCount; i++ ){
			strings[i] = scanner.next();
			decode(strings[i]);
		}
	}
	
	public static void decode(String message){
		HashMap<Character, IntermediateResult> intermediateResults = new HashMap<Character, IntermediateResult>();
		
		char currentMsgChar = message.charAt(0);
		int receivedCharIndex = indexOf(currentMsgChar);
		
		// initialization: what is the most likely first character?
		for(int i = 0; i < alphabet.length; i++ ){
			char currentChar = alphabet[i];
			IntermediateResult currentIntermResult = new IntermediateResult(currentChar);
			
			double currProbability = errorProbMatrix[i][receivedCharIndex];
			
			if( currentIntermResult.getBestCurrentProb() < currProbability ){
				currentIntermResult.setBestCurrentProb(currProbability);
			}
				
			intermediateResults.put(currentChar, currentIntermResult);
		}
		
		double smallestDifferenceForMaxProb = Double.MAX_VALUE;
		
		for( int msgIndex = 1; msgIndex < message.length(); msgIndex++ ){
			currentMsgChar = message.charAt(msgIndex);
			receivedCharIndex = indexOf(currentMsgChar);
			
			HashMap<Character, IntermediateResult> previousResults = intermediateResults;
			intermediateResults = new HashMap<Character, IntermediateResult>();
			
			for( IntermediateResult previousResult : previousResults.values() ){
				// move previous most likely character to prefix
				previousResult.finalise();
				
				char currentPrevChar = previousResult.getCharacter();
				int prevCharIndex = indexOf( currentPrevChar );
				
				// build from this previous most likely character: examine all possible transitions
				for( int transProbIndex = 0; transProbIndex < alphabet.length; transProbIndex++ ){
					double currentTransitionProbability = transitionProbMatrix[prevCharIndex][transProbIndex];
					char correspondingChar = alphabet[transProbIndex];
					double correspondingErrorProbability = errorProbMatrix[transProbIndex][receivedCharIndex];
					double totalCharProbability = currentTransitionProbability + correspondingErrorProbability;
					
					IntermediateResult correspondingIntermediateResult = intermediateResults.get(correspondingChar);
					if( correspondingIntermediateResult == null ){
						correspondingIntermediateResult = new IntermediateResult( correspondingChar );
						correspondingIntermediateResult.setMaxLogLikelihoodPrior( previousResult.getMaxLogLikelihoodPrior() );
						correspondingIntermediateResult.setMaxLogLikelihoodPrefix( previousResult.getMaxLogLikelihoodPrefix() );
						intermediateResults.put(correspondingChar, correspondingIntermediateResult);
					}
					
					double bestTotalProbabilitySoFar = correspondingIntermediateResult.getMaxLogLikelihoodPrior() + correspondingIntermediateResult.getBestCurrentProb();
					double currentTotalProbability = previousResult.getMaxLogLikelihoodPrior() + totalCharProbability;
					double difference = Math.abs(currentTotalProbability - bestTotalProbabilitySoFar);
					
					if( difference < EPSILON ){
						String currentBestMsg = correspondingIntermediateResult.getMaxLogLikelihoodPrefix()+correspondingIntermediateResult.getCharacter();
						String currentConsideredMsg = previousResult.getMaxLogLikelihoodPrefix()+correspondingChar;
					}
					if( bestTotalProbabilitySoFar < currentTotalProbability ){
						if( currentTotalProbability - bestTotalProbabilitySoFar < smallestDifferenceForMaxProb ){
							smallestDifferenceForMaxProb = currentTotalProbability - bestTotalProbabilitySoFar;
						}
						
						correspondingIntermediateResult.setBestCurrentProb(totalCharProbability);
						correspondingIntermediateResult.setMaxLogLikelihoodPrefix(previousResult.getMaxLogLikelihoodPrefix());
						correspondingIntermediateResult.setMaxLogLikelihoodPrior(previousResult.getMaxLogLikelihoodPrior());
						intermediateResults.put(correspondingChar, correspondingIntermediateResult);
					}	
				}	
			}
		}
		//System.out.println("smallest difference: "+smallestDifferenceForMaxProb);
		IntermediateResult maxLikelihoodResult = null;
		double maxLikelihoodProbability = Double.NEGATIVE_INFINITY;
		
		for( IntermediateResult ir : intermediateResults.values() ){
			ir.finalise();
			double currentTotalProbability = ir.getMaxLogLikelihoodPrior();
			
			if( currentTotalProbability > maxLikelihoodProbability ){
				maxLikelihoodProbability = currentTotalProbability;
				maxLikelihoodResult = ir;
			}
			
		}
		System.out.println(maxLikelihoodResult.getMaxLogLikelihoodPrefix());
	}
	
	public static int indexOf( char character ){
		int index = -1;
		
		for( int i = 0; i < alphabet.length; i++ ){
			if( character == alphabet[i] ){
				index = i;
				break;
			}
		}
		
		return index;
	}
}

class IntermediateResult{
	private String maxLogLikelihoodPrefix;
	private double maxLogLikelihoodPrior;
	private double bestCurrentProb;
	private char character;
	
	public IntermediateResult(char c){
		this.maxLogLikelihoodPrefix = "";
		// log(1) = 0
		this.maxLogLikelihoodPrior = 0;
		this.character = c;
		this.bestCurrentProb = Double.NEGATIVE_INFINITY;
	}
	
	public String getMaxLogLikelihoodPrefix() {
		return maxLogLikelihoodPrefix;
	}

	public double getMaxLogLikelihoodPrior() {
		return maxLogLikelihoodPrior;
	}
	
	public double getBestCurrentProb() {
		return bestCurrentProb;
	}
	
	public char getCharacter() {
		return character;
	}
	
	public void setBestCurrentProb( double probability ){
		this.bestCurrentProb = probability;
	}
	
	public void setMaxLogLikelihoodPrefix( String prefix ) {
		this.maxLogLikelihoodPrefix = prefix;
	}
	
	public void setMaxLogLikelihoodPrior( double probability ) {
		this.maxLogLikelihoodPrior = probability;
	}
	
	public void finalise(){
		this.maxLogLikelihoodPrior += bestCurrentProb;
		this.maxLogLikelihoodPrefix += this.character;
		this.bestCurrentProb = Double.NEGATIVE_INFINITY;
	}
	
	public String toString(){
		return maxLogLikelihoodPrefix +" (" +maxLogLikelihoodPrior +") " +character +" (" +bestCurrentProb +")";
	}
}
