洛谷传送门
BZOJ传送门
题目描述
几乎所有操作系统的命令行界面(CLI)中都支持文件名的通配符匹配以方便用户。最常见的通配符有两个,一个是星号(*
),可以匹配
0
0
0个及以上的任意字符:另一个是问号(?
),可以匹配恰好一个任意字符。现在需要你编写一个程序,对于给定的文件名列表和一个包含通配符的字符串,判断哪些文件可以被匹配。
输入输出格式
输入格式:
第一行是一个由小写字母和上述通配符组成的字符串。第二行包含一个整数 n n n,表示文件个数。接下来 n n n行,每行为一个仅包含小写字母字符串,表示文件名列表。
输出格式:
输出
n
n
n行,每行为YES
或NO
,表示对应文件能否被通配符匹配。
输入输出样例
输入样例#1:
*aca?ctc
6
acaacatctc
acatctc
aacacatctc
aggggcaacacctc
aggggcaacatctc
aggggcaacctct
输出样例#1:
YES
YES
YES
YES
YES
NO
说明
对于 100 % 100\% 100%的数据
- 字符串长度不超过 100000 100000 100000
- 1 ≤ n ≤ 100 1 \le n\le 100 1≤n≤100
- 通配符个数不超过 10 10 10
解题分析
貌似这玩意叫做正则表达式? C + + 11 C++11 C++11直接资瓷匹配?
我们可以发现实际上比较影响我们匹配的就是*
, 因为它会打乱我们的匹配位置, 所以直接在每个*
的位置断开, 再维护每段内有几段英文字母以及其哈希值, 然后贪心找每段最早能在哪里匹配到就可以了。
如果*
在最后面和最前面需要特判,我们可以直接在模板串和匹配串最前面和最后面加入A
, 就可以不用特判了。
细节比较多, 码的时候要格外注意边界问题。
代码如下:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define ll long long
#define BASE 233ll
#define MOD 19420817ll
#define gc getchar()
#define MX 100500
char mod[MX], buf[MX];
int tot, lena, lenb, seg;
struct INFO
{
int cnt, totlen;
int len[15], start[15];
ll key[15];
}dat[15];
int from[15], to[15], pos[15];
int n;
ll mul[MX], val[MX];
IN bool ismatch(R int ps, R int id)
{
ll hs1;
for (R int i = 1; i <= dat[id].cnt; ++i)
{
hs1 = (val[ps + dat[id].start[i] + dat[id].len[i] - 1] - val[ps + dat[id].start[i] - 1] * mul[dat[id].len[i]] % MOD + MOD) % MOD;
if (hs1 != dat[id].key[i]) return false;
}
return true;
}
int main(void)
{
ll hs;
int pre, cur = 1, bd;
scanf("%s", mod + 2);
lena = std::strlen(mod + 2); lena++;
mod[1] = 'A';
pos[0] = 0; mod[++lena] = 'A';
for (R int i = 1; i < lena; ++i) if (mod[i] == '*')
pos[++tot] = i, dat[tot].totlen = pos[tot] - pos[tot - 1] - 1;
pos[++tot] = lena + 1; dat[tot].totlen = lena - pos[tot - 1];
W (cur <= lena)
{
W (!isalpha(mod[cur])) ++cur;
from[++seg] = cur;
W (isalpha(mod[cur])) ++cur;
to[seg] = cur - 1;
}
cur = 1;
for (R int i = 1; i <= tot; ++i)
{
W (to[cur] < pos[i] && cur <= seg)
{
++dat[i].cnt;
dat[i].len[dat[i].cnt] = to[cur] - from[cur] + 1;
dat[i].start[dat[i].cnt] = from[cur] - pos[i - 1] - 1;
hs = 0;
for (R int i = from[cur]; i <= to[cur]; ++i) hs = (hs * BASE % MOD + mod[i]) % MOD;
dat[i].key[dat[i].cnt] = hs;
++cur;
}
}
mul[0] = 1;
for (R int i = 1; i <= 100000; ++i) mul[i] = mul[i - 1] * BASE % MOD;
scanf("%d", &n);
nx: W (n--)
{
scanf("%s", buf + 2); lenb = std::strlen(buf + 2); ++lenb;
buf[1] = buf[++lenb] = 'A';
val[1] = buf[1];
for (R int i = 2; i <= lenb; ++i) val[i] = (val[i - 1] * BASE % MOD + buf[i]) % MOD;
if (!ismatch(1, 1)) {puts("NO"); continue;}
cur = dat[1].totlen + 1;
for (R int i = 2; i < tot; ++i)//特殊判断第一段和最后一段
{
if (!dat[i].cnt)
{
cur += dat[i].totlen;
continue;
}
bd = lenb - dat[i].totlen + 1;
for (; cur <= bd; ++cur)
{
if (ismatch(cur, i))
{
cur += dat[i].totlen;
goto st;
}
}
puts("NO"); goto nx;
st: ;
}
if (cur <= lenb - dat[tot].totlen + 1)
{
if (ismatch(lenb - dat[tot].totlen + 1, tot)) puts("YES");
else puts("NO");
}
else puts("NO");
}
}