题意

本题的意思就是给出一段带有 $ ? $ 与 \(*\) 的字符串

(在下面称为\(s\)),

$ ? $ 必须占据一个字符位置, \(*\) 可以占据任意位置,

求下面给出几段(在下面称为\(ss\))中能够匹配的字符串。

思路


前言

本题最可恶的一点是,如果s的第一段/最后一段是字符,那么ss中最开始/最后也必须是一样的字符。

另外,本题我使用了hash + 前缀,如果不太熟悉的话可以了解一下~传送门

举个栗子~

如样例,s为*aca?ctc,我们就可以将它分为

\(*\) ,aca, $ ? $ ,ctc 共四段。

对于每一段,我们用一个add数组来判断它的种类,

用co记录它的段数,字符串对应2,\(*\) 对应1,$ ? $ 对应0:


scanf("%s",s+1);lens=strlen(s+1);
if(s[1]<'a'||s[1]>'z')co=0;else add[1]=2;
for(int i=1;i<=lens;i++)
{
if(s[i]>='a'&&s[i]<='z')
{
len[co]++;
f[co]=f[co]*131+s[i];
}
else if(s[i]=='*') {add[++co]=1;if(i!=lens&&s[i+1]>='a'&&s[i+1]<='z')add[++co]=2;}
else{co++;if(i!=lens&&s[i+1]>='a'&&s[i+1]<='z')add[++co]=2;}
}

注意,由于开头字符不好判断,所以这里加了一个特判,

来记录开头是字符串的情况。

判断

预处理好了,那么,如何进行判断呢?

这里,我用了 $ doit $ 与 \(ask\) 两个自定义函数,

doit用来对可以自由匹配的字符种类进行判断处理,

ask用来对“ ? ”后的字符进行判断处理。

两个函数中都使用了key,k两个参数,

key记录了到哪个字符(指针),k记录了到第几段。

对于doit:


void doit(int key,int k)
{
if(k>co){can=1;return;}//段数数完了,说明满足条件;
if(add[k]==2)//字符
{
for(int i=key+len[k]-1;i<=le;i++)
if(ff[i]-ff[i-len[k]]*p[len[k]]==f[k])//寻找符合的解进行doit;
{doit(i+1,k+1);if(can)return;}
return;
}
if(add[k]==1)//星号
{
doit(key,k+1);
if(can)return;
return;
}
if(add[k]==0)//问号
{
ask(key+1,k+1);return;
}
}

对于ask:


void ask(int key,int k)
{
if(k>co){can=1;return;}
if(add[k]==2)
{
if(ff[key+len[k]-1]-ff[key-1]*p[len[k]]==f[k])doit(key+len[k],k+1);
}
else
{
if(add[k]==1){if(add[k+1]==0){
for(int i=key+2;i<=le;i++)
if(ff[i+len[k+2]-1]-ff[i-1]*p[len[k+2]]==f[k+2])doit(i+len[k+2],k+3);}
doit(key,k+1);}//星号,判断下一个是不是问号
如果是问号就要找到能够匹配的子串进行doit;
else ask(key+1,k+1);//问号继续ask;
}
}

收尾

到这里,万事俱备,只欠东风,进行我们华丽的结束吧~

接下来就该读入与判断了:

	p[0]=1;
for(int i=1;i<=100000;i++)p[i]=p[i-1]*131;
int n=read();
while(n--)
{can=0;
scanf("%s",ss+1);le=strlen(ss+1);
for(int i=1;i<=le;i++)ff[i]=ff[i-1]*131+ss[i];
if(add[1]==2)if(ff[len[1]]-ff[0]*p[len[1]]!=f[1]){printf("NO\n");continue;}//前言中说的特殊情况
if(add[co]==2)if(ff[le]-ff[le-len[co]]*p[len[co]]!=f[co]){printf("NO\n");continue;}
doit(1,1);
if(can)printf("YES\n");else printf("NO\n");
}
return 0;

CODE


#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
#define ull unsigned long long
int read(){int x=0;char ch=getchar();while(ch<'0'||ch>'9')ch=getchar();while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x;}
char s[100005],ss[100005];
int lens,len[25],co=1,le,k,key,cnt,add[25];bool can;
ull f[25],ff[100010],p[100010];
void ask(int,int);
void doit(int,int);
void ask(int key,int k)
{
if(k>co){can=1;return;}
if(add[k]==2)
{
if(ff[key+len[k]-1]-ff[key-1]*p[len[k]]==f[k])doit(key+len[k],k+1);
}
else
{
if(add[k]==1){if(add[k+1]==0){for(int i=key+2;i<=le;i++)if(ff[i+len[k+2]-1]-ff[i-1]*p[len[k+2]]==f[k+2])doit(i+len[k+2],k+3);}doit(key,k+1);}
else ask(key+1,k+1);
}
}
void doit(int key,int k)
{
if(k>co){can=1;return;}
if(add[k]==2)
{
for(int i=key+len[k]-1;i<=le;i++)
if(ff[i]-ff[i-len[k]]*p[len[k]]==f[k])
{doit(i+1,k+1);if(can)return;}
return;
}
if(add[k]==1)
{
doit(key,k+1);
if(can)return;
return;
}
if(add[k]==0)
{
ask(key+1,k+1);return;
}
}
int main()
{
scanf("%s",s+1);lens=strlen(s+1);
if(s[1]<'a'||s[1]>'z')co=0;else add[1]=2;
for(int i=1;i<=lens;i++)
{
if(s[i]>='a'&&s[i]<='z')
{
len[co]++;
f[co]=f[co]*131+s[i];
}
else if(s[i]=='*') {add[++co]=1;if(i!=lens&&s[i+1]>='a'&&s[i+1]<='z')add[++co]=2;}
else{co++;if(i!=lens&&s[i+1]>='a'&&s[i+1]<='z')add[++co]=2;}
}
p[0]=1;
for(int i=1;i<=100000;i++)p[i]=p[i-1]*131;
int n=read();
while(n--)
{can=0;
scanf("%s",ss+1);le=strlen(ss+1);
for(int i=1;i<=le;i++)ff[i]=ff[i-1]*131+ss[i];
if(add[1]==2)if(ff[len[1]]-ff[0]*p[len[1]]!=f[1]){printf("NO\n");continue;}
if(add[co]==2)if(ff[le]-ff[le-len[co]]*p[len[co]]!=f[co]){printf("NO\n");continue;}
doit(1,1);
if(can)printf("YES\n");else printf("NO\n");
}
return 0;
}

结语

这道题我也调了有好久了,甚至都有些舍不得了,所以写下了本篇题解,也是我的第一篇题解

如果对你有帮助,求个赞qwq

LuoguP3167通配符匹配的更多相关文章

  1. bzoj 3507: [Cqoi2014]通配符匹配

    Description 几乎所有操作系统的命令行界面(CLI)中都支持文件名的通配符匹配以方便用户.最常见的通配符有两个,一个是星号(“”’),可以匹配0个及以上的任意字符:另一个是问号(“?”),可 ...

  2. 【BZOJ-3507】通配符匹配 DP + Hash

    3507: [Cqoi2014]通配符匹配 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 372  Solved: 156[Submit][Statu ...

  3. [Swift]LeetCode44. 通配符匹配 | Wildcard Matching

    Given an input string (s) and a pattern (p), implement wildcard pattern matching with support for '? ...

  4. 【BZOJ3507】通配符匹配(哈希,动态规划)

    [BZOJ3507]通配符匹配(哈希,动态规划) 题面 BZOJ 题解 对于匹配唯一存在影响的只有通配符,而\(?\)的影响也并不大,所以唯一需要仔细考虑的是\(*\). 考虑一个\(dp\),设\( ...

  5. LeetCode(44): 通配符匹配

    Hard! 题目描述: 给定一个字符串 (s) 和一个字符模式 (p) ,实现一个支持 '?' 和 '*' 的通配符匹配. '?' 可以匹配任何单个字符. '*' 可以匹配任意字符串(包括空字符串). ...

  6. [BZOJ3507]通配符匹配

    3507: [Cqoi2014]通配符匹配 Time Limit: 10 Sec  Memory Limit: 128 MB Description 几乎所有操作系统的命令行界面(CLI)中都支持文件 ...

  7. [LeetCode][Facebook面试题] 通配符匹配和正则表达式匹配,题 Wildcard Matching

    开篇 通常的匹配分为两类,一种是正则表达式匹配,pattern包含一些关键字,比如'*'的用法是紧跟在pattern的某个字符后,表示这个字符可以出现任意多次(包括0次). 另一种是通配符匹配,我们在 ...

  8. WildcardMatching和Regex,通配符匹配和正则表达式匹配

    WildcardMatching:通配符匹配 算法分析: 1. 二个指针i, j分别指向字符串.匹配公式. 2. 如果匹配,直接2个指针一起前进. 3. 如果匹配公式是*,在字符串中依次匹配即可. 注 ...

  9. BZOJ3507 [Cqoi2014]通配符匹配

    题意 几乎所有操作系统的命令行界面(CLI)中都支持文件名的通配符匹配以方便用户.最常见的通配符有两个,一个是星号("*"),可以匹配0个及以上的任意字符:另一个是问号(" ...

随机推荐

  1. nginx的基本使用

    下载: https://nginx.org/en/download.html  Window下安装: 下载好了之后直接解压就行了.(解压目录切记别含有中文) 启动:1️⃣直接双击nginx.exe2️ ...

  2. Kubernetes 1.13.3 部署 Prometheus+Grafana-7.5.2(最新版本踩坑)

    本教程直接在 Kubernetes 1.13.3 版本上安装 Prometheus 和 Grafana-7.5.2,至于它们的原理和概念就不再赘述,这里就直接开始操作. Git 下载相关 YAML 文 ...

  3. 软件测试跟踪工具Bugzilla的安装 - Linux版本

    首先查看Linux当前版本 输入"uname -a ",可显示电脑以及操作系统的相关信息 输入"cat /proc/version",说明正在运行的内核版本 输 ...

  4. CTF-OldDriver-writeup

    题目信息: 有个年轻人得到了一份密文,身为老司机的你能帮他看看么? 附件:enc.txt [{"c": 73660675747411714617220651332429160804 ...

  5. MyBatis学习笔记(一):MAVEN的下载,安装与环境配置和在IDEA中配置maven

    一.下载 官网下载 :http://maven.apache.org/download.cgi 网速慢的也可以下载我配置好的国内阿里云仓库的.以下以我配置好的为例: 下载链接:https://pan. ...

  6. 关于hive核心

    一.DDL数据定义 1.创建数据库 1)创建一个数据库,数据库在 HDFS 上的默认存储路径是/user/hive/warehouse/*.db. hive (default)> create ...

  7. CF1032G Chattering

    CF1032G Chattering 题意 思路 对于每一个位置,它转移的范围是确定的. 对于一段可以走到的区间,我们可以求出区间中所有点再能走到区间范围. 于是这个就可以倍增进行转移. 如何快速求出 ...

  8. 插入排序(insertion_sort)——Python实现

      # 插入排序 # 作用:对给出的n个顺序不定的数进行排序 # 输入:任意数组A # 输出:按顺序排列的数组A # 时间复杂度 n(n-1) 至 (n(n-1))/2   # 插入排序过程 # 第一 ...

  9. 【阅读笔记】Java核心技术卷一 #4.Chapter6

    6 接口.lambda 表达式与内部类 6.1 接口 6.1.1 接口概念 接口绝不能含有实例域:但在接口中可以定义常量,被自动设为 public static final 接口中的所有方法自动地属于 ...

  10. thinkPHP5 5.0.23 远程代码执行漏洞

    修改数据包 POST /index.php?s=captcha HTTP/1.1 Host: 192.168.49.2:8080 User-Agent: Mozilla/5.0 (Macintosh; ...