1. 题目描述
有两个长度为$10^5$的字符串,其中一个仅包含小写字母,称之为源串;另一个包含?与*通配符的模式串,并且通配符的个数不超过10。求模式串是否能匹配源串?

2. 基本思路
这其实是一道RegularExpression-Matching问题。一般化的解法就是构建自动机,然后去在这个自动机上搜索源串,是否被接收即为答案。这个一般化方法的时间复杂度为$O(|x||y|)$。显然,这里不适用。题目中的限定条件通配符个数不超过10使得,不需要构建完整的自动机。我们可以将模式串$d$改写为
$d_0 \cdot (?|*) \cdot d_1 \cdot (?|*) \cdots d_k$,其中$d_0, d_1, \cdots d_k$可以为$\varepsilon$。
因此,我们可以换一个思路。首先,利用kmp算法我们可以求得子串$d_i, i \in [0, k]$在源串$s$上的匹配位置,称之为end-point。
则对通配符分情况讨论:
(1) ?:仅匹配一个字符,那么d_k匹配的有效的end-point的下一个位置仍然可以匹配;
(2) *:可以匹配任意个字符,那么d_k首次匹配的end-point的后续位置都可以匹配。
注意,这里的有效有特殊含义,有效不仅要保证这次的子串$d_i$匹配end-point,同时一定要满足上一次的位置$end-point - |d_i|$同样是可以匹配的。
因此,算法的框架就变成了:
(1) 对模式串进行分割,分割点为?或*;
(2) 在源串中使用kmp算法搜索子串的end-point并且标记;
(3) 利用前次的匹配标记数组$ep$与kmp的标记$visit$共同确定这次的匹配标记;
(4) 对长度为0的字符串单独讨论;
(5) 对不含通配符的模式串,直接strcmp。

3. 代码

 /* 3901 */
#include <iostream>
#include <sstream>
#include <string>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <vector>
#include <deque>
#include <bitset>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <cstring>
#include <climits>
#include <cctype>
#include <cassert>
#include <functional>
#include <iterator>
#include <iomanip>
using namespace std;
//#pragma comment(linker,"/STACK:102400000,1024000") #define sti set<int>
#define stpii set<pair<int, int> >
#define mpii map<int,int>
#define vi vector<int>
#define pii pair<int,int>
#define vpii vector<pair<int,int> >
#define rep(i, a, n) for (int i=a;i<n;++i)
#define per(i, a, n) for (int i=n-1;i>=a;--i)
#define clr clear
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define all(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define lson l, mid, rt<<1
#define rson mid+1, r, rt<<1|1 #ifndef ONLINE_JUDGE
const int maxn = ;
#else
const int maxn = 1e5+;
#endif
const int maxm = ;
char s[maxn], d[maxn];
bool ep[maxm][maxn];
bool visit[maxn];
char ss[maxn];
int nxt[maxn], slen, dlen; void getnext(char *s, int len) {
int i, j; nxt[] = -;
i = ;
j = -;
while (i < len) {
if (j==- || s[i]==s[j]) {
++i;
++j;
nxt[i] = j;
} else {
j = nxt[j];
}
}
} void findEndPoint(char *ss, int len) {
int i = , j = ; getnext(ss, len);
memset(visit, false, sizeof(visit));
while (i < slen) {
if (s[i] == ss[j]) {
++i;
++j;
} else {
j = nxt[j];
if (j == -) {
j = ;
++i;
}
}
if (j == len) {
visit[i] = true;
}
}
} void solve() {
slen = strlen(s);
dlen = strlen(d);
int gid = ;
int i = , l = ; {
// fast check
bool flag = true;
rep(k, , dlen) {
if (d[k]=='?' || d[k]=='*') {
flag = false;
break;
}
} if (flag) {
if (strcmp(s,d)==)
puts("YES");
else
puts("NO");
return ;
}
} memset(ep, false, sizeof(ep));
ep[gid++][] = true;
while (i < dlen) {
if (islower(d[i])) {
ss[l++] = d[i++];
continue;
} ss[l] = '\0';
if (d[i]=='?') {
if (l == ) {
rep(i, , slen+)
ep[gid][i+] = ep[gid-][i];
} else {
findEndPoint(ss, l);
rep(i, , slen+) {
if (ep[gid-][i] && visit[i+l]) {
ep[gid][i+l+] = true;
}
}
}
} else if (d[i]=='*') {
if (l == ) {
int fir = slen+;
rep(i, , slen+) {
if (ep[gid-][i]) {
fir = i;
break;
}
} rep(i, fir, slen+)
ep[gid][i] = true;
} else {
findEndPoint(ss, l);
int fir = slen + ;
rep(i, , slen+) {
if (ep[gid-][i] && visit[i+l]) {
fir = i + l;
break;
}
} rep(i, fir, slen+)
ep[gid][i] = true;
}
} l = ;
++gid;
++i;
} if (l > ) {
ss[l] = '\0';
findEndPoint(ss, l);
rep(i, , slen+) {
if (ep[gid-][i] && visit[i+l]) {
ep[gid][i+l] = true;
}
}
++gid;
} if (ep[gid-][slen])
puts("YES");
else
puts("NO");
} int main() {
ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
freopen("data.in", "r", stdin);
freopen("data.out", "w", stdout);
#endif while (scanf("%s", s)!=EOF) {
scanf("%s", d);
solve();
} #ifndef ONLINE_JUDGE
printf("time = %d.\n", (int)clock());
#endif return ;
}

【HDOJ】3901 Wildcard的更多相关文章

  1. 【leetcode】44. Wildcard Matching

    题目如下: 解题思路:本题和[leetcode]97. Interleaving String非常相似,同样可以采用动态规划的方法.记dp[i][j] = 1或者0 表示pattern[0:i]是否匹 ...

  2. 【HDOJ】4729 An Easy Problem for Elfness

    其实是求树上的路径间的数据第K大的题目.果断主席树 + LCA.初始流量是这条路径上的最小值.若a<=b,显然直接为s->t建立pipe可以使流量最优:否则,对[0, 10**4]二分得到 ...

  3. 【HDOJ】【3506】Monkey Party

    DP/四边形不等式 裸题环形石子合并…… 拆环为链即可 //HDOJ 3506 #include<cmath> #include<vector> #include<cst ...

  4. 【HDOJ】【3516】Tree Construction

    DP/四边形不等式 这题跟石子合并有点像…… dp[i][j]为将第 i 个点开始的 j 个点合并的最小代价. 易知有 dp[i][j]=min{dp[i][j] , dp[i][k-i+1]+dp[ ...

  5. 【HDOJ】【3480】Division

    DP/四边形不等式 要求将一个可重集S分成M个子集,求子集的极差的平方和最小是多少…… 首先我们先将这N个数排序,容易想到每个自己都对应着这个有序数组中的一段……而不会是互相穿插着= =因为交换一下明 ...

  6. 【HDOJ】【2829】Lawrence

    DP/四边形不等式 做过POJ 1739 邮局那道题后就很容易写出动规方程: dp[i][j]=min{dp[i-1][k]+w[k+1][j]}(表示前 j 个点分成 i 块的最小代价) $w(l, ...

  7. 【HDOJ】【3415】Max Sum of Max-K-sub-sequence

    DP/单调队列优化 呃……环形链求最大k子段和. 首先拆环为链求前缀和…… 然后单调队列吧<_<,裸题没啥好说的…… WA:为毛手写队列就会挂,必须用STL的deque?(写挂自己弱……s ...

  8. 【HDOJ】【3530】Subsequence

    DP/单调队列优化 题解:http://www.cnblogs.com/yymore/archive/2011/06/22/2087553.html 引用: 首先我们要明确几件事情 1.假设我们现在知 ...

  9. 【HDOJ】【3068】最长回文

    Manacher算法 Manacher模板题…… //HDOJ 3068 #include<cstdio> #include<cstring> #include<cstd ...

随机推荐

  1. 【BZOJ】【3790】神奇项链

    Manacher算法/DP 找出所有的回文串,看做是一个个线段,那么问题就转化成了用最少的线段将整个区间覆盖起来,可以重叠,那么这就是一个DP了= = Orz ZKY大爷,让蒟蒻开眼界了……头一次知道 ...

  2. struct {0}初始化

    #include <iostream> struct MyStruct { MyStruct(int a) { a = b = ; } int a; int b; }; int main( ...

  3. 驱动笔记 - ioctl

    #include <linux/ioctl.h> 定义命令 _IO(type,nr) 没有参数的命令 _IOR(type,nr,datatype) 从驱动中读数据 _IOW(type,nr ...

  4. 100个经典的C算法

    1.题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔 子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数 为多少? #include<stdio.h&g ...

  5. 快速编写HTML,CSS代码的有力工具Emmet插件

    Emmet 是一个编辑器插件,它以一种简写的语法规则可用于快速编写html或css文档内容,它支持多种编辑器. 从官网:http://emmet.io/ 可下载各个编辑器的插件.notepad++ 插 ...

  6. HTML5 canvas 绘图步骤

    1.先把canvas选出来,不选出来你往哪儿画! var oCan=  document.getElementById('xxx'); 2.声明基于 canvas 的context对象,没他你怎么调用 ...

  7. jQuery对象和javascript对象互换

    jquery变js var obj=$("dom"); 或 var obj=jQuery("dom"); js 变 jquery var $jobj=$(obj ...

  8. POJ 2013

    #include <iostream> #include <string> #define MAXN 20 using namespace std; string _m[MAX ...

  9. 刘汝佳 算法竞赛-入门经典 第二部分 算法篇 第五章 3(Sorting/Searching)

    第一题:340 - Master-Mind Hints UVA:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Item ...

  10. Shell实现跳板机,为什么用跳板机

    整理自:http://blog.chinaunix.net/uid-22101889-id-3167454.html 注意:请谨慎使用,到现在为止,使用了,我还没找到改回去的方法. 1.     问题 ...