題面
題意:有很多個只包含4個字母的短串和一個長串
問長串至少改幾個字符就不包含任何短串
用短串建AC自動機,標記好所有結束狀態
設 爲長度爲i,後綴爲狀態j的最小更改數
每次枚舉4個字母轉移就可以了
#include <iostream>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
#define mmst(a, b) memset(a, b, sizeof(a))
#define mmcp(a, b) memcpy(a, b, sizeof(b))
typedef long long LL;
const int N=2020;
int n,len,ans,Violet;
int son[N][4],fail[N],cnt;
bool ed[N];
int q[N];
int f[N][N];
char s[N];
int ch(char cc)
{
if(cc=='A')
return 0;
if(cc=='C')
return 1;
if(cc=='T')
return 2;
return 3;
}
int main()
{
while(1)
{
cin>>n;
if(n==0)
return 0;
Violet++;
cnt=1;
mmst(ed,0);
for(int i=0;i<N;i++)
for(int j=0;j<4;j++)
son[i][j]=0;
ans=1001;
for(int i=1;i<=n;i++)
{
int now=1;
scanf("%s",s+1);
len=strlen(s+1);
for(int j=1;j<=len;j++)
{
if(!son[now][ch(s[j])])
son[now][ch(s[j])]=++cnt;
now=son[now][ch(s[j])];
}
ed[now]=1;
}
int hh=1,tt=1;
fail[1]=q[1]=1;
while(hh<=tt)
{
int hy=q[hh++];
for(int i=0;i<4;i++)
if(son[hy][i])
{
q[++tt]=son[hy][i];
fail[son[hy][i]]= (hy==1) ? 1 : son[fail[hy]][i];
ed[son[hy][i]]|=ed[fail[son[hy][i]]];
}
else
son[hy][i]= (hy==1) ? 1 : son[fail[hy]][i];
}
scanf("%s",s+1);
len=strlen(s+1);
for(int i=0;i<=len;i++)
for(int j=1;j<=cnt;j++)
f[i][j]=1001;
f[0][1]=0;
for(int i=1;i<=len;i++)
for(int j=1;j<=cnt;j++)
for(int k=0;k<4;k++)
if(!ed[son[j][k]])
f[i][son[j][k]]=min(f[i][son[j][k]],f[i-1][j]+ ((ch(s[i])==k) ? 0 : 1));
for(int j=1;j<=cnt;j++)
ans=min(ans,f[len][j]);
cout<<"Case "<<Violet<<": "<<((ans!=1001) ? ans : -1)<<endl;
}
return 0;
}