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;
}
posted @ 2020-11-19 21:21  Tartarus_li  阅读(112)  评论(0编辑  收藏  举报