题意

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

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

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

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

思路


前言

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

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

举个栗子~

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

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

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

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


  1. scanf("%s",s+1);lens=strlen(s+1);
  2. if(s[1]<'a'||s[1]>'z')co=0;else add[1]=2;
  3. for(int i=1;i<=lens;i++)
  4. {
  5. if(s[i]>='a'&&s[i]<='z')
  6. {
  7. len[co]++;
  8. f[co]=f[co]*131+s[i];
  9. }
  10. else if(s[i]=='*') {add[++co]=1;if(i!=lens&&s[i+1]>='a'&&s[i+1]<='z')add[++co]=2;}
  11. else{co++;if(i!=lens&&s[i+1]>='a'&&s[i+1]<='z')add[++co]=2;}
  12. }

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

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

判断

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

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

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

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

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

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

对于doit:


  1. void doit(int key,int k)
  2. {
  3. if(k>co){can=1;return;}//段数数完了,说明满足条件;
  4. if(add[k]==2)//字符
  5. {
  6. for(int i=key+len[k]-1;i<=le;i++)
  7. if(ff[i]-ff[i-len[k]]*p[len[k]]==f[k])//寻找符合的解进行doit;
  8. {doit(i+1,k+1);if(can)return;}
  9. return;
  10. }
  11. if(add[k]==1)//星号
  12. {
  13. doit(key,k+1);
  14. if(can)return;
  15. return;
  16. }
  17. if(add[k]==0)//问号
  18. {
  19. ask(key+1,k+1);return;
  20. }
  21. }

对于ask:


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

收尾

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

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

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

CODE


  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<iostream>
  5. using namespace std;
  6. #define ull unsigned long long
  7. 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;}
  8. char s[100005],ss[100005];
  9. int lens,len[25],co=1,le,k,key,cnt,add[25];bool can;
  10. ull f[25],ff[100010],p[100010];
  11. void ask(int,int);
  12. void doit(int,int);
  13. void ask(int key,int k)
  14. {
  15. if(k>co){can=1;return;}
  16. if(add[k]==2)
  17. {
  18. if(ff[key+len[k]-1]-ff[key-1]*p[len[k]]==f[k])doit(key+len[k],k+1);
  19. }
  20. else
  21. {
  22. 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);}
  23. else ask(key+1,k+1);
  24. }
  25. }
  26. void doit(int key,int k)
  27. {
  28. if(k>co){can=1;return;}
  29. if(add[k]==2)
  30. {
  31. for(int i=key+len[k]-1;i<=le;i++)
  32. if(ff[i]-ff[i-len[k]]*p[len[k]]==f[k])
  33. {doit(i+1,k+1);if(can)return;}
  34. return;
  35. }
  36. if(add[k]==1)
  37. {
  38. doit(key,k+1);
  39. if(can)return;
  40. return;
  41. }
  42. if(add[k]==0)
  43. {
  44. ask(key+1,k+1);return;
  45. }
  46. }
  47. int main()
  48. {
  49. scanf("%s",s+1);lens=strlen(s+1);
  50. if(s[1]<'a'||s[1]>'z')co=0;else add[1]=2;
  51. for(int i=1;i<=lens;i++)
  52. {
  53. if(s[i]>='a'&&s[i]<='z')
  54. {
  55. len[co]++;
  56. f[co]=f[co]*131+s[i];
  57. }
  58. else if(s[i]=='*') {add[++co]=1;if(i!=lens&&s[i+1]>='a'&&s[i+1]<='z')add[++co]=2;}
  59. else{co++;if(i!=lens&&s[i+1]>='a'&&s[i+1]<='z')add[++co]=2;}
  60. }
  61. p[0]=1;
  62. for(int i=1;i<=100000;i++)p[i]=p[i-1]*131;
  63. int n=read();
  64. while(n--)
  65. {can=0;
  66. scanf("%s",ss+1);le=strlen(ss+1);
  67. for(int i=1;i<=le;i++)ff[i]=ff[i-1]*131+ss[i];
  68. if(add[1]==2)if(ff[len[1]]-ff[0]*p[len[1]]!=f[1]){printf("NO\n");continue;}
  69. if(add[co]==2)if(ff[le]-ff[le-len[co]]*p[len[co]]!=f[co]){printf("NO\n");continue;}
  70. doit(1,1);
  71. if(can)printf("YES\n");else printf("NO\n");
  72. }
  73. return 0;
  74. }

结语

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

如果对你有帮助,求个赞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. ESP32的ULP 协处理器笔记

    1.ULP 协处理器是一个功耗极低的协处理器设备,无论主 CPU 是处于正常运行模式还是 Deep-sleep 模式,ULP 协处理器都可以独立运行.超低功耗协处理器的补充使得 ESP32 能够胜任一 ...

  2. XDFZOI 月赛 201905 Sliver

    组题人自己组完过后,才发现自己还是太弱了... T1 简单模拟. 按照游戏规则直接模拟显然是不明智的,所以我们可以像石头剪刀布一样,将判断改变为检验. 同时,我们发现,一共只有48种牌,所以我们可以直 ...

  3. Automation Framework Design 自动化框架设计思想

    从2007年到2017年,十年内自动化测试工具层出不穷,各种工具在运用一段时间之后,各个公司都会有测试架构师对于目前的自动化测试工具进行框架定制设计. 从惠普2007年GDCC推出的的WebDrivi ...

  4. python 读取 写入txt文件

    filename = 'pi_digits.txt' with open(filename) as f:#默认以只读方式打开文件 lines = f.readlines()#读取所有行,结果为列表,每 ...

  5. 在 .NET 中创建对象的几种方式的对比

    在 .net 中,创建一个对象最简单的方法是直接使用 new (), 在实际的项目中,我们可能还会用到反射的方法来创建对象,如果你看过 Microsoft.Extensions.DependencyI ...

  6. springMVC-6-restful_CRUD

    1.大体框架 POJO层代码 Employee @Data public class Employee { private Integer id; private String lastName; p ...

  7. etcd学习(3)-grpc使用etcd做服务发现

    grpc通过etcd实现服务发现 前言 服务注册 服务发现 负载均衡 集中式LB(Proxy Model) 进程内LB(Balancing-aware Client) 独立 LB 进程(Externa ...

  8. Leetcode:面试题 04.04. 检查平衡性

    Leetcode:面试题 04.04. 检查平衡性 Leetcode:面试题 04.04. 检查平衡性 Talk is cheap . Show me the code . /** * Definit ...

  9. innodb引擎相关参数

    1.innodb_flush_log_at_trx_commit (双一标准之一) 作用:主要控制了innodb将log buffer中的数据写入日志文件并flush磁盘的时间点,取值分别为0.1.2 ...

  10. 小鹤双拼win10一键恢复布局

    起因 一直用的小鹤双拼布局,最近重装系统又要重新配置,麻烦 尝试 查找对应注册表设置,找到以下路径包含相应配置 HKEY_CURRENT_USER\Software\Microsoft\InputMe ...