BZOJ 3507 [CQOI2014]通配符匹配 (哈希 + dp)
题目链接:https://darkbzoj.tk/problem/3507
以通配符为分界点将原字符串分开,通配符也算一个字符串
\(dp[j][i]\) 表示到第 \(j\) 个匹配字符串能否匹配到第 \(i\) 个位置
分情况转移即可
#include<bits/stdc++.h>
using namespace std;
const int maxn = 200010;
const int M = 998244353;
const int base = 131;
int N, n;
int f[maxn], p[maxn];
int dp[50][maxn];
int v[maxn], l[maxn], cnt = 0;
char A[maxn], s[maxn];
int Get_Hash(int L, int R){
return ((f[R] - 1ll * f[L - 1] * p[R - L + 1] % M) % M + M) % M;
}
int main(){
p[0] = 1;
for(int i = 1 ; i <= 200000 ; ++i) p[i] = 1ll * p[i-1] * base % M;
scanf("%s", A + 1);
int len = strlen(A + 1);
int le = 0;
A[len + 1] = '?';
for(int i = 1 ; i <= len + 1; ++i){
if(A[i] == '*' || A[i] == '?'){
if(f[i - 1] != 0) v[++cnt] = f[i - 1]; l[cnt] = le;
f[i] = 0; le = 0;
if(i <= len){
if(A[i] == '*') v[++cnt] = -1;
if(A[i] == '?') v[++cnt] = -2;
}
continue;
}
if(i == len + 1) break;
f[i] = (1ll * f[i - 1] * base % M + A[i] - 'a' + 1) % M;
++le;
}
cin >> N;
while(N--){
memset(dp, 0, sizeof(dp));
scanf("%s", s + 1);
n = strlen(s + 1);
f[0] = 0;
for(int i = 1 ; i <= n ; ++i){
f[i] = (1ll * f[i - 1] * base % M + s[i] - 'a' + 1) % M;
}
dp[0][0] = 1; int la = 0, flag = 0;
for(int j = 1 ; j <= cnt ; ++j){
flag = n + 1;
for(int i = 0 ; i <= n ; ++i){
if(v[j] < 0) {
if(i > 0 && v[j] == -2){
dp[j][i] = dp[j - 1][i - 1];
if(dp[j][i] == 1) flag = min(flag, i);
}
if(v[j] == -1){
if(i >= la) dp[j][i] = 1;
if(dp[j][i]) flag = min(flag, i);
}
}
else if(i >= l[j]){
int val = Get_Hash(i - l[j] + 1, i);
if(val == v[j] && dp[j - 1][i - l[j]]) dp[j][i] = 1;
if(dp[j][i]) flag = min(flag, i);
}
}
la = flag;
}
if(dp[cnt][n]) printf("YES\n");
else printf("NO\n");
}
return 0;
}