LuoguP3167通配符匹配
题意
本题的意思就是给出一段带有 $ ? $ 与 \(*\) 的字符串
(在下面称为\(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通配符匹配的更多相关文章
- bzoj 3507: [Cqoi2014]通配符匹配
Description 几乎所有操作系统的命令行界面(CLI)中都支持文件名的通配符匹配以方便用户.最常见的通配符有两个,一个是星号(“”’),可以匹配0个及以上的任意字符:另一个是问号(“?”),可 ...
- 【BZOJ-3507】通配符匹配 DP + Hash
3507: [Cqoi2014]通配符匹配 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 372 Solved: 156[Submit][Statu ...
- [Swift]LeetCode44. 通配符匹配 | Wildcard Matching
Given an input string (s) and a pattern (p), implement wildcard pattern matching with support for '? ...
- 【BZOJ3507】通配符匹配(哈希,动态规划)
[BZOJ3507]通配符匹配(哈希,动态规划) 题面 BZOJ 题解 对于匹配唯一存在影响的只有通配符,而\(?\)的影响也并不大,所以唯一需要仔细考虑的是\(*\). 考虑一个\(dp\),设\( ...
- LeetCode(44): 通配符匹配
Hard! 题目描述: 给定一个字符串 (s) 和一个字符模式 (p) ,实现一个支持 '?' 和 '*' 的通配符匹配. '?' 可以匹配任何单个字符. '*' 可以匹配任意字符串(包括空字符串). ...
- [BZOJ3507]通配符匹配
3507: [Cqoi2014]通配符匹配 Time Limit: 10 Sec Memory Limit: 128 MB Description 几乎所有操作系统的命令行界面(CLI)中都支持文件 ...
- [LeetCode][Facebook面试题] 通配符匹配和正则表达式匹配,题 Wildcard Matching
开篇 通常的匹配分为两类,一种是正则表达式匹配,pattern包含一些关键字,比如'*'的用法是紧跟在pattern的某个字符后,表示这个字符可以出现任意多次(包括0次). 另一种是通配符匹配,我们在 ...
- WildcardMatching和Regex,通配符匹配和正则表达式匹配
WildcardMatching:通配符匹配 算法分析: 1. 二个指针i, j分别指向字符串.匹配公式. 2. 如果匹配,直接2个指针一起前进. 3. 如果匹配公式是*,在字符串中依次匹配即可. 注 ...
- BZOJ3507 [Cqoi2014]通配符匹配
题意 几乎所有操作系统的命令行界面(CLI)中都支持文件名的通配符匹配以方便用户.最常见的通配符有两个,一个是星号("*"),可以匹配0个及以上的任意字符:另一个是问号(" ...
随机推荐
- Flask(9)- 蓝图的基本使用
前言 在前面的例子中,所有的页面处理逻辑都是放在同一个文件中,随着业务代码的增加,将所有代码都放在单个程序文件中是非常不合适的 不仅会让阅读代码变得困难,而且会给后期维护带来麻烦 Flask 中使用蓝 ...
- Hive源码上手及问题解决
一.编译准备 1.下载源码包 https://github.com/apache/hive/archive/refs/tags/rel/release-2.3.7.zip 或使用git直接拉取 无法解 ...
- Java | 标识符 & 关键字
标识符是什么? 标识符 标识符是指在程序中,我们自己定义的内容.比如类的名字.方法的名字和变量的名字等等,都是标识符.在我们写的第一个程序当中,我们给类起名叫做Hello 也叫做标识符. 命名规则 标 ...
- Python之一行代码将网址URL转换成动态彩色二维码
先在 pycharm 安装 myqr.或者,Python3 必装,然后命令行 pip install myqr 也可. 将我的微信公众号网址:http://weixin.qq.com/r/hRMQC ...
- CocoaPods 私有化
一.创建所需要的代码仓库 创建 Spec 私有索引库(ZFSpec),用来存放本地spec 创建模块私有库(ZFPodProject),用来存放项目工程文件 二.私有索引库添加到本地 CocoaPod ...
- HCNA Routing&Switching之动态路由协议OSPF DR和BDR
前文我们了解了OSPF建立邻居关系的条件,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/15032907.html:今天我们来聊一聊OSPF中的DR和BDR: ...
- 算法leetcode二分算法
二分算法通常用于有序序列中查找元素: 有序序列中是否存在满足某条件的元素: 有序序列中第一个满足某条件的元素的位置: 有序序列中最后一个满足某条件的元素的位置. 思路很简单,细节是魔鬼. 一.有序序列 ...
- 二进制方式安装 k8s
推荐个好用的安装k8s的工具 https://github.com/easzlab/kubeasz 该工具基于二进制方式部署 k8s, 利用 ansible-playbook 实现自动化 1.1 ...
- php使用curl模拟post请求
废话不多说,直接上代码,做个笔记. $url="http://localhost/header_server.php"; $body = array("mobile&qu ...
- 如何使用Scala的ClassTag
Scala官方文档中对于ClassTag的定义如下: ClassTag[T]保存着在运行时被JVM擦除的类型T的信息.当我们在运行时想获得被实例化的Array的类型信息的时候,这个特性会比较有用. 下 ...