题意

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

(在下面称为\(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. excle名字后面直接跟别的出来

    名字后面直接跟别的出来 =IF($E6="","",VLOOKUP(E6,通讯录!$B$2:$D$1000,3,0)) $E6:是填写位置的地方 VLOOKUP ...

  2. C语言:虚拟地址 和编译模式

    所谓虚拟地址空间,就是程序可以使用的虚拟地址的有效范围.虚拟地址和物理地址的映射关系由操作系统决定,相应地,虚拟地址空间的大小也由操作系统决定,但还会受到编译模式的影响.这节我们先讲解CPU,再讲解编 ...

  3. java使用IO读写文件

    https://www.cnblogs.com/qiaoyeye/p/5383723.html java读写文件的IO流分两大类,字节流和字符流,基类分别是字符:Reader和Writer:字节:In ...

  4. JProfiler监控java应用使用情况,故障情况分析

    1.软件部署(java环境已提前准备) 服务器:centos7.4 https://download-gcdn.ej-technologies.com/jprofiler/jprofiler_linu ...

  5. Python+Scrapy+Crawlspider 爬取数据且存入MySQL数据库

    1.Scrapy使用流程 1-1.使用Terminal终端创建工程,输入指令:scrapy startproject ProName 1-2.进入工程目录:cd ProName 1-3.创建爬虫文件( ...

  6. linux相关的常用站点

    1  http://cdimage.ubuntu.com/ ubuntu各个发行版的总集服务器 2 http://www.rpmfind.net/ 各种RPM包

  7. github在不同电脑上协同开发

    当我换了电脑后,开发自己的github项目遇到了一些问题. 首先,git clone 'repository url'拉取下来项目,开始开发项目发.修改了一些文件后,当要git commit, git ...

  8. iTextSharp导出PDF模板(报告)

    using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.IO;us ...

  9. Pb代理工具之mitmproxy

    mitmproxy 一 . mitmproxy介绍 mitmproxy 就是用于 MITM 的 proxy,MITM 即中间人攻击(Man-in-the-middle attack). 不同于 fid ...

  10. 开机时自动启动的AutoHotkey脚本

    ;;; 开机时自动启动的AutoHotkey脚本;; 此脚本修改时间 2019年06月18日20时48分;; 计时器创建代码段 ------------------------------------ ...