[Luogu P3167] [BZOJ 3507] [CQOI2014]通配符匹配

版权声明:欢迎转载蒟蒻博客,但请注明出处: https://blog.csdn.net/LPA20020220/article/details/84193613

洛谷传送门

BZOJ传送门

题目描述

几乎所有操作系统的命令行界面(CLI)中都支持文件名的通配符匹配以方便用户。最常见的通配符有两个,一个是星号(*),可以匹配 0 0 个及以上的任意字符:另一个是问号(?),可以匹配恰好一个任意字符。现在需要你编写一个程序,对于给定的文件名列表和一个包含通配符的字符串,判断哪些文件可以被匹配。

输入输出格式

输入格式:

第一行是一个由小写字母和上述通配符组成的字符串。第二行包含一个整数 n n ,表示文件个数。接下来 n n 行,每行为一个仅包含小写字母字符串,表示文件名列表。

输出格式:

输出 n n 行,每行为YESNO,表示对应文件能否被通配符匹配。

输入输出样例

输入样例#1:

*aca?ctc
6
acaacatctc
acatctc
aacacatctc
aggggcaacacctc
aggggcaacatctc
aggggcaacctct

输出样例#1:

YES
YES
YES
YES
YES
NO

说明

对于 100 % 100\% 的数据

  • 字符串长度不超过 100000 100000
  • 1 n 100 1 \le n\le 100
  • 通配符个数不超过 10 10

解题分析

貌似这玩意叫做正则表达式? 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");
	}
}

猜你喜欢

转载自blog.csdn.net/LPA20020220/article/details/84193613