bzoj3507【CQOI2014】通配符匹配

148 篇文章 0 订阅
78 篇文章 1 订阅

3507: [Cqoi2014]通配符匹配

Time Limit: 10 Sec   Memory Limit: 128 MB
Submit: 309   Solved: 129
[ Submit][ Status][ Discuss]

Description

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

Input

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

Output

输出n行,每行为“YES”或“NO”,表示对应文件能否被通配符匹配。

Sample Input

*aca?ctc
6
acaacatctc
acatctc
aacacatctc
aggggcaacacctc
aggggcaacatctc
aggggcaacctct

Sample Output

YES
YES
YES
YES
YES
NO

HINT

对于1 00%的数据

  ·字符串长度不超过1 00000

  ·  1 <=n<=100

  ·通配符个数不超过10




DP+哈希

f[i][j]表示第i个通配符和第j个字符能否匹配,然后搞搞转移,注意两种通配符的区别。




#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define ull unsigned long long
#define maxn 100005
#define base 13131
using namespace std;
char ch[maxn],s[maxn];
int n,len,cnt,pos[15];
bool f[15][maxn];
ull n1[maxn],n2[maxn],p[maxn];
inline ull h1(int st,int ed)
{
	if (st>ed) return 0;
	return n1[ed]-n1[st-1]*p[ed-st+1];
}
inline ull h2(int st,int ed)
{
	if (st>ed) return 0;
	return n2[ed]-n2[st-1]*p[ed-st+1];
}
int main()
{
//	freopen("input.in","r",stdin);
	scanf("%s",ch+1);
	len=strlen(ch+1);
	F(i,1,len) if (ch[i]<'a'||ch[i]>'z') pos[++cnt]=i;
	pos[++cnt]=len+1;ch[++len]='?';
	F(i,1,len) n1[i]=(n1[i-1]*base+ch[i]);
	p[0]=1;
	F(i,1,100000) p[i]=p[i-1]*base;
	scanf("%d",&n);
	while (n--)
	{
		scanf("%s",s+1);
		len=strlen(s+1);s[++len]='#';
		F(i,1,len) n2[i]=n2[i-1]*base+s[i];
		memset(f,0,sizeof(f));
		f[0][0]=true;
		F(i,0,cnt-1)
		{
			if (ch[pos[i]]=='*')
			{
				F(j,1,len) if (f[i][j-1]) f[i][j]=true;
			}
			F(j,0,len) if (f[i][j]&&h1(pos[i]+1,pos[i+1]-1)==h2(j+1,j+pos[i+1]-pos[i]-1))
			{
				if (ch[pos[i+1]]=='?') f[i+1][j+pos[i+1]-pos[i]]=true;
				else f[i+1][j+pos[i+1]-pos[i]-1]=true;
			}
		}
		if (f[cnt][len]) puts("YES");
		else puts("NO");
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值