[AHOI2005]病毒檢測
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]病毒檢測