Description
科学家们在Samuel星球上的探险仍在继续。非常幸运的,在Samuel星球的南极附近,探险机器人发现了一个巨大的冰湖!机器人在这个冰湖中搜集到了许多RNA片段运回了实验基地。科学家们经过几个昼夜的研究,发现这些RNA片段中有许多是未知的病毒!每个RNA片段都是由A、C、T、G组成的序列。科学家们也总结出了Samuel星球上的“病毒模版片段”。一个模版片段是由A、C、T、G的序列加上通配符 * 和 ? 来表示。其中 * 的意思是可以匹配上0个或任意多个字符,而 ? 的意思是匹配上任意一个字母。如果一个RNA片段能够和“病毒模版片段”相匹配,那么这个RNA片段就是未知的病毒。例如,假设“病毒模版片段”为A*G?C。RNA片段:AGTC,AGTGTC都是未知的病毒,而RNA片段AGTGC则不是病毒。由于,机器人搜集的这些RNA片段中除去病毒的其他部分都具有非常高的研究价值。所以科学家们希望能够分辨出其中哪些RNA片段不是病毒,并将不是病毒的RNA片段运回宇宙空间站继续进行研究。科学家将这项任务交给了小联。现在请你为小联编写程序统计哪些RNA片段不是病毒。
Input
第一行有一个字符串,由A、C、T、G、*、? 组成。表示“病毒模版片段”。“病毒模版片段”的长度不超过1000。第二行有一个整数N(0<N<500),表示机器人搜集到的RNA片段的数目。随后的N行,每一行有一个字符串,由A、C、T、G组成,表示一个RNA片段。每个RNA片段的长度不超过500。注意:“病毒模版片段”和RNA片段的长度都至少为1。
Output
只有一行输出,为整数M,即不是病毒的RNA片段的数目。
Sample Input
A*G?C
3
AGTC
AGTGTC
AGTGC
Sample Output
1
这题写法其实很暴力……由于数据范围很小,所以我们直接对RNA片段建一棵trie树,然后用模板片段去爆搜,开个bool数组剪枝一下就好了
然后空间……64MB,MLE(然鹅洛谷可以跑过去)
所以我们换个想法,考虑dp,设\(f[i][j]\)表示模板匹配到第\(i\)个位置,RNA片段匹配到第\(j\)位的情况,如果不是'*'就直接转移一位,否则就用一串转移,单次判断RNA复杂度\(O(n^2)\),所以总复杂度为\(O(n^3)\)
/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){
static char buf[1000000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){
int x=0,f=1;char ch=gc();
for (;ch<'0'||ch>'9';ch=gc()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=gc()) x=(x<<1)+(x<<3)+ch-'0';
return x*f;
}
inline int read(){
int x=0,f=1;char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
return x*f;
}
inline void print(int x){
if (x<0) putchar('-'),x=-x;
if (x>9) print(x/10);
putchar(x%10+'0');
}
const int N=5e2;
bool f[(N<<1)+10][N+10];
char T[(N<<1)+10];
int c[(N<<1)+10];
int main(){
scanf("%s",T+1);
int lenT=strlen(T+1),Q=read(),Ans=Q;
while (Q--){
static char s[N+10];
memset(f,0,sizeof(f));
memset(c,63,sizeof(c));
scanf("%s",s+1);
int len=strlen(s+1);
f[0][0]=1;
for (int i=1;i<=lenT;i++){
if (T[i]!='*'){
for (int j=1;j<=len;j++){
if (T[i]=='?'||T[i]==s[j]){
f[i][j]|=f[i-1][j-1];
if (T[i-1]=='*'&&c[i-1]<j) f[i][j]=1;
}
}
}else{
if (i==1) f[i][0]=1;
for (int j=1;j<=len;j++){
f[i][j]|=(f[i-1][j]|f[i][j-1]);
if (f[i][j]) c[i]=min(c[i],j);
}
}
}
if (f[lenT][len]) Ans--;
}
printf("%d\n",Ans);
return 0;
}