BZOJ 3507 [CQOI2014]萬用字元匹配 (雜湊 + dp)
阿新 • • 發佈:2020-11-20
題目連結: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; }