/*
    题意:给出一些病毒串,一个原串,问怎么调整原串的顺序使得跟最多的病毒串匹配

    抄解题报告:
    自动机+DP。设主串有na个A、nc个C、ng个G、nt个T,于是题意转化为用na个A、
    nc个C、ng个G、nt个T生成一个新串,使模式串匹配次数最大。先将模式串生成自动机
    〔trie图〕,然后在这上面进行DP,状态可表示为dp[d,s],d为自动机状态,
    s表示由ma个A、mc个C、mg个G、mt个T的生成串
    〔s可表示为ma*(nc+1)*(ng+1)*(nt+1)+mc*(ng+1)*(nt+1)+mg*(nt+1)+mt〕,
    转移为O(4),总复杂度O(500*11^4*4) 
    
    那种表示方法就是变进制吧

    直接DP(root,s)会超时
    Qinz说这题卡时紧
    我用他的那种dfs才能过,他是先dfs枚举出状态,然后对这个状态递推计算,好快

    比较神奇,不用管顺序的,就记录个数
*/

#include
<cstdio>
#include
<cstring>
#include
<algorithm>
#include
<queue>
#include
<map>

using namespace std;

const int MAXN = 520;

struct Node
{
    Node 
*ch[4] , *next;
    
int id , match;
}
;

Node nodes[MAXN] , 
*Trie , *SuperRoot;
int alloc;

Node 
*newNode()
{
    memset(
&nodes[alloc] , 0 , sizeof(nodes[0]));
    nodes[alloc].id 
= alloc;
    
return &nodes[alloc++];
}


//int getID(char ch)
//{
//    if(ch=='A')return 0;
//    if(ch=='C')return 1;
//    if(ch=='G')return 2;
//    if(ch=='T')return 3;
//}

int getID[200];

void insert(Node * &root, char *s)
{
    
if(*== 0)root->match++;
    
else
    
{
        
int id = getID[*s];
        
if(root->ch[id] == 0)root->ch[id] = newNode();
        insert(root
->ch[id],s+1);
    }

}


void buildTrie()
{
    
for(int i = 0 ; i<4; i++)
        SuperRoot
->ch[i] = Trie;
    Trie
->next = SuperRoot;
    queue
<Node*>Q;
    Q.push(Trie);
    
while(!Q.empty())
    
{
        Node 
*= Q.front() ; Q.pop();
        
for(int i = 0 ; i<4; i++)
        
{
            
if(p->ch[i])
            
{
                p
->ch[i]->next = p->next->ch[i];
                p
->ch[i]->match += p->next->ch[i]->match;//要加这个
                Q.push(p->ch[i]);
            }

            
else p->ch[i] = p->next->ch[i];
        }

    }

}


int val[5];
int num[5];
int dp[MAXN][MAXN*30];


int DP(Node *root, int s)//当前在节点root 剩下可用的字符s 最后能获得的最大值
{
    
if(s==0)return root->match;
    
int id = root->id;
    
int &ans = dp[id][s];
    
if(ans != -1)return ans;//
    ans = 0;

    
int _s = s , t = 1;
    
for(int i = 3 ; i>= 0;s/=(num[i]+1),i--)
    
{
        
if(s % (num[i]+1== 0)continue;
        ans 
= max(ans,DP(root->ch[i] , _s - val[i]) );
    }

    
return ans += root->match;//root此时有占一个字符,但不是属于s的
}


int _num[4];

void dfs(int s , int deep)
{
    
if(deep == 4)//dp[i][s] 在节点i处,剩余s个字符的最大值,节点i不占字符
    {
        
for(int i = 1 ; i < alloc ; i++)
            
for(int j = 0 ; j < 4; j++)
                
if(_num[j])
                
{
                    
int jj = nodes[i].ch[j]->id;
                    dp[i][s] 
= max(dp[i][s] , dp[jj][s-val[j]] + nodes[jj].match);//
                }

        
return ;
    }


    
for(int i =  0 ;  i <= num[deep] ; i++ , s+=val[deep])
    
{
        _num[deep] 
= i;
        dfs(s,deep
+1);
    }

}


int main()
{

#ifdef ONLINE_JUDGE
#else
    freopen(
"in","r",stdin);
#endif
    getID[
'A'= 0;
    getID[
'C'= 1;
    getID[
'G'= 2;
    getID[
'T'= 3;
    
char str[100];
    
for(int n ,t = 1;scanf("%d",&n) ,n ; t++)
    
{
        alloc 
= 0 ;
        SuperRoot 
= newNode();
        Trie 
= newNode();

        
for(int i = 0 ; i < n; i++)
        
{
            scanf(
"%s",str);
            insert(Trie,str);
        }


        buildTrie();

        scanf(
"%s",str);
        memset(num,
0,sizeof(num));
        
for(int i = 0 ; str[i] ; i++)
        
{
            num[getID[str[i]]]
++;
        }


        
int total = 1;
        
for(int i = 0 ; i < 4; i++)
        
{
            total 
*= (num[i]+1);
        }

        num[
4= 0;
        val[
4= 1;
        
for(int i = 3 ; i>=0 ;i--)
        
{
            val[i] 
= val[i+1]*(num[i+1]+1);
        }

        val[
4= total;

        
for(int i = 0 ; i < alloc ; i++)
            
for(int j = 0 ; j <= total ; j++)
                dp[i][j] 
= 0;//-1;
        dfs(0,0);
        
        printf(
"Case %d: %d\n",t,dp[1][total-1]);//DP(Trie,total-1));
    }

    
return 0;
}