3507: [Cqoi2014]通配符匹配
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 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
6
acaacatctc
acatctc
aacacatctc
aggggcaacacctc
aggggcaacatctc
aggggcaacctct
Sample Output
YES
YES
YES
YES
YES
NO
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;
}