/*
    題意:給出一些病毒串,一個原串,問怎么調整原串的順序使得跟最多的病毒串匹配

    抄解題報告:
    自動機+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;
}