分类
标签
2-SAT AC自动机 BFS CDQ dfs DP fail树 FFT FFT&NTT FWT hash KD-Tree KMP LCA SPFA STL Tarjan Treap Trie 主席树 乱搞 二分 二分图匹配 二分答案 二维SPFA 交互 位运算 其他 最小生成树 分块 区间DP 半平面交 博弈论 可持久化 可持久化Trie树 后缀数组 图库 平衡树 并查集 插头DP 数学 数论 无旋Treap 日记 暴力 权值树状数组 栈 树DP 树套树 树状数组 树贪心 概率DP 模拟 欧拉定理 点分治 状压DP 生成函数 矩阵乘 线性规划 线段树 组合 网络流 群论 莫比乌斯反演 计算几何 贪心 费用流 高斯消元
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 long
const 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/