void solve(char *str,int N)
{
int i,j,k,Len,pos,s;
Len = strlen(str);
memset(dp[1],0x11,sizeof(dp[1]));
dp[1][0][0] = 0;
for(i=0;i<Len;i++)
{
memset(dp[next],0x11,sizeof(dp[next]));
for(j=0;j<tot;j++)
{
for(k=0;k<(1<<N);k++)
{
if(dp[now][j][k]>=INF){continue;}
dp[next][j][k] = MIN(dp[next][j][k],dp[now][j][k]+1);
pos = str[i] - 'a';
s = ch[j][pos];
dp[next][s][k|sta[s]] = MIN(dp[next][s][k|sta[s]],dp[now][j][k]);
}
}
}
int ans = INF;
int num = (Len+1)&1;
int full = (1<<N)-1;
for(i=0;i<tot;i++)
{
if(dp[num][i][full]==INF){continue;}
ans = MIN(ans,dp[num][i][full]);
}
if(ans == INF){cout<<"Impossible"<<endl;}
else{cout<<ans<<endl;}
}
#include<iostream>
#include<string>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#define MAXN 505
#define SSIZE 4
using namespace std;
int MAX(int a,int b){return a>b?a:b;}
struct AC_Auto
{
int ch[MAXN][SSIZE];
int fail[MAXN];
int time[MAXN];
int tot;
void MakeNode(int &x)
{
x = tot++;
memset(ch[x],0,sizeof(ch[x]));
fail[x] = time[x] = 0;
}
void Init()
{
int k = tot = 0;
MakeNode(k);
}
int idx(int c)
{
if(c=='A'){return 0;}
if(c=='T'){return 1;}
if(c=='G'){return 2;}
if(c=='C'){return 3;}
}
void build(char *str)
{
int i,k,Len,p = 0;
Len = strlen(str);
for(i=0;i<Len;i++)
{
k = idx(str[i]);
if(!ch[p][k])
{
MakeNode(ch[p][k]);
}
p = ch[p][k];
}
time[p] ++ ;
}
void GetFail()
{
queue<int>que;
int i,t,f,s,ff;
for(i=0;i<SSIZE;i++)
{
t = ch[0][i];
if(t){que.push(t);}
}
while(!que.empty())
{
f = que.front();
que.pop();
for(i=0;i<SSIZE;i++)
{
s = ch[f][i];
ff = fail[f];
if(s)
{
fail[s] = ch[ff][i];
time[s] += time[fail[s]];
que.push(s);
}
else
{
ch[f][i] = ch[ff][i];
}
}
}
}
int bit[4],num[4];
int dp[11*11*11*11+5][MAXN];
int solve(char *str)
{
memset(num,0,sizeof(num));
memset(bit,0,sizeof(bit));
int Len,i,j,k;
Len = strlen(str);
for(i=0;i<Len;i++)
{
num[idx(str[i])]++;
}
bit[0] = (num[1]+1)*(num[2]+1)*(num[3]+1); //A
bit[1] = (num[2]+1)*(num[3]+1); //T
bit[2] = (num[3]+1); //G
bit[3] = 1; //C
memset(dp,-1,sizeof(dp));
dp[0][0] = 0;
int A,T,G,C,s;
for(A=0;A<=num[0];A++)
{
for(T=0;T<=num[1];T++)
{
for(G=0;G<=num[2];G++)
{
for(C=0;C<=num[3];C++)
{
s = A*bit[0] + T*bit[1] + G*bit[2] + C*bit[3];
for(j=0;j<tot;j++)
{
if(dp[s][j]==-1){continue;} //非法状态剪枝 非法状态不转移
for(k=0;k<SSIZE;k++)
{
if(k == 0 && A == num[0])continue; /*我们的进制是刚好按照目标串的情况来划分的。所以其他的多余状态会导致进位。而造成了错误*/
if(k == 1 && T == num[1])continue;
if(k == 2 && G == num[2])continue;
if(k == 3 && C == num[3])continue;
dp[s+1*bit[k]][ch[j][k]] = MAX(dp[s+1*bit[k]][ch[j][k]],dp[s][j]+time[ch[j][k]]);
}
}
}
}
}
}
int ans = 0;
s = num[0]*bit[0] + num[1]*bit[1] + num[2]*bit[2] + num[3]*bit[3];
for(i=0;i<tot;i++)
{
ans = MAX(ans,dp[s][i]);
}
return ans;
}
}AC;
char STR[20];
char SS[50];
int main()
{
int N,i,res,cas = 1;
while(scanf("%d",&N)!=EOF&&N)
{
AC.Init();
for(i=0;i<N;i++)
{
scanf("%s",STR);
AC.build(STR);
}
AC.GetFail();
scanf("%s",SS);
res = AC.solve(SS);
printf("Case %d: %d
",cas++,res);
}
return 0;
}
/*
这个重组。题意是可以交换任意两个碱基的位置。
求交换之后的串能够含有上述的串最多的。
其实这个原串就是规定了对应碱基的个数。
*/