【[AHOI2005]病毒檢測】
阿新 • • 發佈:2019-01-02
\(Trie\) 樹+搜尋
我用的是\(dfs\)
首先對於將所有的RNA片段都建到\(Trie\)樹裡去,之後來匹配那個模板串就好了
如果是匹配的位置是字母,那麼我們就繼續往下匹配
如果是\(?\),我們必須要略過\(Trie\)樹上的一位去匹配
如果是\(*\),我們可以先考慮直接忽略這一位,也可以直接把這一位當成\(?\)來看,或者是在\(Trie\)樹上略過一位,但是在模板串上的匹配仍為當前位置,這樣就能實現在\(Trie\)樹上忽略多位進行匹配了
一旦某一位匹配成功了,我們如果還有狀態到達這一步就沒有什麼必要了,所以開一個\(bitset\)來進行記憶化就好了
程式碼
#include<iostream> #include<cstring> #include<cstdio> #include<queue> #include<bitset> #define re register #define maxn 500005 int son[maxn][4],flag[maxn]; int n,m,cnt,L,ans; char S[1001],T[1001]; std::bitset<1001> f[maxn]; inline int read() { char c=getchar(); int x=0; while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar(); return x; } inline int ch(char p) { if(p=='A') return 0; if(p=='G') return 1; if(p=='T') return 2; if(p=='C') return 3; } inline void ins() { int len=strlen(S+1); int now=0; for(re int i=1;i<=len;i++) { if(!son[now][ch(S[i])]) son[now][ch(S[i])]=++cnt; now=son[now][ch(S[i])]; } flag[now]++; } void dfs(int now,int t) { if(t==L+1)//匹配成功 { ans+=flag[now]; flag[now]=0; return; } if(f[now][t]) return; f[now][t]=1;//記憶化 if(T[t]>='A'&&T[t]<='Z') { if(!son[now][ch(T[t])]) return; dfs(son[now][ch(T[t])],t+1); }//是字母,那麼我們就繼續往下匹配 else { if(T[t]=='?') { for(re int i=0;i<4;i++) if(son[now][i]) dfs(son[now][i],t+1);//在Trie上忽略一位,同時模板串匹配位置加1 } if(T[t]=='*') { dfs(now,t+1);//忽略*,即用0個字元來代替它 for(re int i=0;i<4;i++) if(son[now][i]) dfs(son[now][i],t+1),dfs(son[now][i],t); //第一個dfs直接把這一位當成$?$來看,第二個dfs就能實現一個*代替多個字元 } } } int main() { scanf("%s",T+1); L=strlen(T+1); n=read(); for(re int i=1;i<=n;i++) scanf("%s",S+1),ins(); dfs(0,1); printf("%d\n",n-ans); return 0; }