简要题意

给你一个模式串 \(s\) 和一些待匹配字符串 \(t_i\)

模式串 \(s\)\(\texttt{A,C,T,*,?}\) 组成。其中 \(\texttt{A,C,T}\) 表示这个位置匹配这个字符本身。\(\texttt{*}\) 可以匹配任意个字符(包括 \(0\) 个)。\(\texttt{?}\) 可以匹配一个任意字符。

你需要求出有多少个待匹配字符串无法匹配。

\(1\leq N\lt 500,1\leq |s|,|t_i|\leq 10^3\)

思路

原题的 Bug:RNA 中好像没有 Thymine(胸腺嘧啶)(DNA 才有) 。有 Adenine(腺嘌呤,维生素 B4)、Guanine(鸟嘌呤)、Cytosine(胞嘧啶)、Uracil(尿嘧啶)(这个 DNA 没有)。

对于每一个 \(t\),我们考虑 DP,设 \(f(i,j)\)\(s[1:i]\) 是否与 \(t[1:j]\) 匹配。

则当 \(s_i=\texttt{?}\) 时,可以匹配一个元素,也就是 \(f(i-1,j-1)\)

\(s_i=\texttt{*}\) 时,可以匹配任意个元素,我们分两个情况考虑:

  • 匹配 \(0\) 个,即 \(f(i-1,j)\)
  • 匹配多个,即 \(f(i,j-1)\)。(因为可以大于 \(1\) 个,所以 \(i\) 不需要减 \(1\),直接让 \(\ast\) 发挥它的作用,继续匹配)。

所以 \(f(i,j)=f(i-1,j)\operatorname{Or}f(i,j-1)\)

其他情况在满足前面都匹配上的情况下直接匹配,\(f(i,j)=f(i-1,j-1)\operatorname{And} [s_i=t_j]\)

所以状态转移方程就出来了:

\[f({i,j})=\begin{cases}
&f({i-1,j-1})&s_i=\texttt{?}\\
&f(i-1,j)\operatorname{Or}f(i,j-1)&s_i=\texttt{*}\\
&f(i-1,j-1)\operatorname{And} [s_i=t_j]&\text{otherwise}
\end{cases}
\]

最后看看 \(f(|s|,|t|)\) 是否为 \(\operatorname{false}\) 即可。

最后讲一讲边界,首先显然 \(f_{0,0}=\operatorname{true}\),其次对于所有的 \(s\) 前面的连续的 \(\ast\)\(s_i\)\(f_{i,0}=\operatorname{true}\)

时间复杂度 \(O(n|s||t|)\)

代码

#include <bits/stdc++.h>
#define int long long
#define elif else if
using namespace std;

int n,m;
string s,t;
bool f[505][505];

signed main(){
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>s>>n;
    s=" "+s;
    f[0][0]=1;
    for(int i=1;i<s.size()&&s[i]=='*';i++) f[i][0]=1;
    while(n--){
        cin>>t;
        t=" "+t;
        for(int i=1;i<s.size();i++){
            for(int j=1;j<t.size();j++){
                if(s[i]=='?') f[i][j]=f[i-1][j-1];
                elif(s[i]=='*') f[i][j]=f[i-1][j]||f[i][j-1];
                else f[i][j]=f[i-1][j-1]&&(s[i]==t[j]);
            }
        }
        m+=!f[s.size()-1][t.size()-1];
        for(int i=1;i<s.size();i++){
            for(int j=1;j<t.size();j++) f[i][j]=0;
        }
    }
    cout<<m;
    return 0;
}