BZOJ 3507: [Cqoi2014]通配符匹配(Hash+DP)

Description

几乎所有操作系统的命令行界面(CLI)中都支持文件名的通配符匹配以方便用户。最常见的通配符有两个,一个
是星号(“”’),可以匹配0个及以上的任意字符:另一个是问号(“?”),可以匹配恰好一个任意字符。
现在需要你编写一个程序,对于给定的文件名列表和一个包含通配符的字符串,判断哪些文件可以被匹配。

Input

第一行是一个由小写字母和上述通配符组成的字符串。
第二行包含一个整数n,表示文件个数。
接下来n行,每行为一个仅包含小写字母字符串,表示文件名列表。

Output

输出n行,每行为“YES”或“NO”,表示对应文件能否被通配符匹配。


题解:
可以发现唯一存在影响的只有通配符’*‘和’?’,而‘?'的影响也不大,稍微判断一下就可以,所以唯一需要考虑的是‘ *’,考虑设dp[i][j]表示已经匹配了i个通配符,下面的字符串匹配到了第j个字符的方案是否存在。

详解在代码中↓


AC代码:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#include<ext/rope>
using namespace std;
using namespace __gnu_cxx;
#define ull unsigned long long
#define pii pair<int,int>
#define mp(a,b) make_pair(a,b)
const int MAXN = 1e5+10;
const int BASE = 131;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
char ch[MAXN],s[MAXN];
ull hash1[MAXN],hash2[MAXN],pw[MAXN];
int pos[50],tot,n,m; bool dp[20][MAXN];
signed main(){
#ifndef ONLINE_JUDGE
    freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin);
#endif // ONLINE_JUDGE
    scanf("%s",s+1); n=strlen(s+1)+1; s[n]='?';
    pw[0]=1; for(int i=1;i<=1e5;i++) pw[i]=pw[i-1]*BASE;
    for(int i=1;i<=n;i++) hash1[i]=hash1[i-1]*BASE+s[i];
    for(int i=1;i<=n;i++) if(s[i]=='*' || s[i]=='?') pos[++tot]=i;
    //提取通配符
    int Q; scanf("%d",&Q);
    while(Q--){
        memset(dp,false,sizeof(dp)); dp[0][0]=true;
        scanf("%s",ch+1); m=strlen(ch+1); ch[++m]='#';
        for(int i=1;i<=m;i++)hash2[i]=hash2[i-1]*BASE+ch[i];
        for(int i=0;i<=tot;i++){
        	//如果是'*',如果j这个位置的方案是存在的,那么之后的方案也可以通过'*'拓展而来
        	//所以只要有一个位置的方案存在,后面的方案也应该都存在
            if(s[pos[i]]=='*')
                for(int j=1;j<=m;j++) dp[i][j]|=dp[i][j-1];
            for(int j=0;j<=m;j++){//枚举下面匹配到j位置了
                if(!dp[i][j]) continue;
                //提取区间判断相等
                int l1=j+1,r1=j+(pos[i+1]-pos[i])-1;
                int l2=pos[i]+1,r2=pos[i+1]-1;
                if(hash2[r1]-hash2[l1-1]*pw[r1-l1+1]==hash1[r2]-hash1[l2-1]*pw[r2-l2+1]){
                //两段子串可以匹配上,那么r1这个位置肯定是存在方案的
                    if(s[pos[i+1]]=='?') dp[i+1][r1+1]=true;
                    //如果下一个是'?',那么下一位字符也能匹配到
                    else dp[i+1][r1]=true;
                }
            }
        }
        puts(dp[tot][m] ? "YES":"NO");
    }
    return 0;
}
发布了152 篇原创文章 · 获赞 1 · 访问量 2695

猜你喜欢

转载自blog.csdn.net/qq_43544481/article/details/103916037
今日推荐