1. 程式人生 > >[AHOI2005]病毒檢測

[AHOI2005]病毒檢測

任務 sca line algo set 總結 getchar size pac

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;
}

[AHOI2005]病毒檢測