[AHOI2005]病毒检测
题目描述
科学家们在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片段不是病毒。
输入输出格式
输入格式:
第一行有一个字符串,由A、C、T、G、*、? 组成。表示“病毒模版片段”。“病毒模版片段”的长度不超过1000。第二行有一个整数N(0<N<500),表示机器人搜集到的RNA片段的数目。随后的N行,每一行有一个字符串,由A、C、T、G组成,表示一个RNA片段。每个RNA片段的长度不超过500。注意:“病毒模版片段”和RNA片段的长度都至少为1。
输出格式:
只有一行输出,为整数M,即不是病毒的RNA片段的数目。
输入输出样例
输入样例#1:
A*G?C
3
AGTC
AGTGTC
AGTGC
输出样例#1: 复制
1
说明
输入中的RNA片段AGTGC不是病毒。
有好多方法啊.....dp,字典树啊
trie树
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<queue>
const int maxn=1000+233;
using namespace std;
char ch[maxn];
typedef pair<int,int> par;
int n;
int ans;
short moon[maxn];
int tr[maxn*maxn][10];
int no[maxn];
int cnt,fin[maxn*maxn];
inline short change(char c){
if(c=='A')return 1;
else if(c=='G')return 2;
else if(c=='C')return 3;
else if(c=='T')return 4;
else if(c=='?')return 5;
else return 6;
}
inline void add(){
cin>>ch;
int now=0;
int len=strlen(ch);
for(int i=0;i<len;i++)no[i]=change(ch[i]);
for(int i=0;i<len;i++){
if( tr[now][ no[i] ] )now=tr[now][ no[i] ];
else cnt++,tr[now][no[i]]=cnt,now=cnt;
}
fin[now]++;
}
queue< pair<int,int> >q;
inline void getans(int P){
q.push(make_pair(1,0));
while(!q.empty()){
par p=q.front();q.pop();
int now=p.second;//second匹配到位置<fir原字符
int point=p.first;
if(moon[point]==6){
q.push(make_pair(point+1,now));
for(int i=1;i<5;i++){
if(tr[now][i]){
q.push(make_pair(point,tr[now][i]));
q.push(make_pair(point+1,tr[now][i]));
}
}
}
else if(moon[point]==5)
for(int i=1;i<5;i++){
if(tr[now][i])q.push(make_pair(point+1,tr[now][i]));
}
else if(moon[point]){
if(tr[now][moon[point]])
q.push(make_pair(point+1,tr[now][moon[point]]));
}
if(point==P+1)
ans+=fin[now],fin[now]=0;
}
cout<<n-ans;
}
int main(){
cin>>ch+1;
int len=strlen(ch+1);
for(int i=1;i<=len;i++)moon[i]=change(ch[i]);
cin>>n;
for(int i=1;i<=n;i++)add();
getans(len);
return 0;
}
DP
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<queue>
const int maxn=1000+233;
using namespace std;
char ch[maxn];
int c[maxn];
int dp[maxn][maxn];
char a[maxn];
int n;
int L;
int ans;
inline bool match(char x,char y){
return (x==y)||(x=='?');
}
inline void add(){
cin>>a+1;
memset(c,0x3f,sizeof c);
memset(dp,0,sizeof dp);
int len=strlen(a+1);
dp[0][0]=1;
for(int i=1;i<=L;i++){
if(ch[i]!='*')
for(int j=1;j<=len;j++){
if(match(ch[i],a[j]))
if(dp[i-1][j-1]||ch[i-1]=='*'&&c[i-1]<j)
dp[i][j]=1;
}
else{
if(i==1)dp[1][0]=1;
for(int j=1;j<=len;j++){
dp[i][j]=dp[i-1][j]|dp[i][j-1];
if(dp[i][j])c[i]=min(c[i],j);
}
}
}
if(!dp[L][len])ans++;
}
int main(){
cin>>ch+1;
L=strlen(ch+1);
cin>>n;
for(;n;n--)add();
cout<<ans;
return 0;
}