410 字
2 分钟
BZOJ 3507 [Cqoi2014]通配符匹配 hash 题解
Description
几乎所有操作系统的命令行界面(CLI)中都支持文件名的通配符匹配以方便用户。最常见的通配符有两个,一个 是星号(“”’),可以匹配0个及以上的任意字符:另一个是问号(“?”),可以匹配恰好一个任意字符。 现在需要你编写一个程序,对于给定的文件名列表和一个包含通配符的字符串,判断哪些文件可以被匹配。
Input
第一行是一个由小写字母和上述通配符组成的字符串。
第二行包含一个整数n,表示文件个数。
接下来n行,每行为一个仅包含小写字母字符串,表示文件名列表。
Output
输出n行,每行为“YES”或“NO”,表示对应文件能否被通配符匹配。
Sample Input
*aca?ctc
6
acaacatctc
acatctc
aacacatctc
aggggcaacacctc
aggggcaacatctc
aggggcaacctct
Sample Output
YES
YES
YES
YES
YES
NO
题解
将原字符串由’*‘分成若干段
记录每一个’?‘的位置
分段hash
将文件首尾先匹配然后在中间贪心的匹配
/* * @Author: WildRage * @Date: 2017-06-17 10:45:09 * @Last Modified by: WildRage * @Last Modified time: 2017-06-17 11:09:39 */#include<cstdio>#include<cstring>#include<algorithm>#include<vector>#include<stack>using namespace std;#define ULL unsigned long longconst ULL base=31;ULL pw[100005],f[15][15],HASH[100005];int pos[15],cnt,num[15],s[15][15],n,lenth;char S[100005],a[100005];ULL get_hash(int l,int r){ return HASH[r]-HASH[l-1]*pw[r-l+1];}bool OK(int i,int k){ for(int j=0;j<=num[k];j++){ if(s[k][j]==0){i++;continue;} if(f[k][j]!=get_hash(i,i+s[k][j]-1))return 0; i+=s[k][j]+1; } return 1;}bool work(char *b){ int len=strlen(b+1); if(!cnt){ if(lenth!=len)return 0; for(int i=1;i<=lenth;i++) if(S[i]!=b[i]&&S[i]!='?')return 0; return 1; } if(len<(pos[1]-1)+(lenth-pos[cnt]))return 0; for(int i=1;i<pos[1];i++)if(S[i]!=b[i]&&S[i]!='?')return 0; for(int i=lenth,j=len;i>pos[cnt];i--,j--) if(S[i]!=b[j]&&S[i]!='?')return 0; for(int i=1;i<=len;i++) HASH[i]=HASH[i-1]*base+b[i]; int MAX=len-(lenth-pos[cnt])+1; int i=pos[1]; for(int k=2;k<=cnt;k++){ while(i<=MAX){ if(OK(i,k))break; i++; } i+=pos[k]-pos[k-1]-1; if(i>MAX) return 0; } return 1;}int main(){ //freopen("match.in","r",stdin); //freopen("match.out","w",stdout); scanf("%s",S+1); lenth=strlen(S+1); pw[0]=1; cnt=0; for(int i=1;i<=100000;i++)pw[i]=pw[i-1]*base; for(int i=1;i<=lenth;i++) if(S[i]=='*') pos[++cnt]=i; for(int i=2;i<=cnt;i++){ num[i]=0; for(int j=pos[i-1]+1;j<pos[i];j++){ if(S[j]=='?'){ num[i]++; continue; } s[i][num[i]]++; f[i][num[i]]=f[i][num[i]]*base+S[j]; } } scanf("%d",&n); while(n--){ scanf("%s",a+1); if(work(a))puts("YES"); else puts("NO"); } //while(1);}
BZOJ 3507 [Cqoi2014]通配符匹配 hash 题解
https://www.nekomio.com/posts/15/