您的位置:首页 > 其它

BZOJ3507通配符匹配(DP + Hash)

2017-08-29 19:02 309 查看
搬运题解系列:http://www.cnblogs.com/DaD3zZ-Beyonder/p/5962702.html

3507: [Cqoi2014]通配符匹配

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 372  Solved: 156

[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


Source


Solution

感觉复杂度有点玄学的做法。

DP+Hash

f[i][j]表示第i个通配符能否匹配到第j个位置。

因为一个*会把字符串分成两段,所以这个*分开的两边一定是要求一样的,这里可以利用hash判断。

然后我们就可以得到通配符串被*分成好几段,这样就可以得到转移。

枚举起点,如果可以匹配就可以转移。

有一些比较方便的处理,比如S最后加一个?,以及s最后加任意一个字符

这样的时间复杂度封顶大概是



















O(N∗k∗len),但是发现这个转移其实时间复杂度是不满的,所以可以AC
#include<bits/stdc++.h>
using namespace std;
#define ULL unsigned long long
#define LL long long
#define MAXN 100010
#define BASE 131
char s1[MAXN],s2[MAXN];
ULL Hash[2][MAXN], pw[MAXN];
bool dp[12][MAXN];
int p[20], t, n;
void Hashtable(char str[], int opt)
{
int len=strlen(str+1);
for(int i=1; i<=len; i++) Hash[opt][i]=Hash[opt][i-1]*BASE+str[i];
}
ULL GetHash(int l, int r, int opt)
{
return r>=l ? Hash[opt][r]-Hash[opt][l-1]*pw[r-l+1] : -1;
}
int main()
{
pw[0]=1;for(int i=1; i<MAXN; i++) pw[i]=pw[i-1]*BASE;
scanf("%s", s1+1);Hashtable(s1, 0);
int len=strlen(s1+1);
for(int i=1; i <=len; i++) if(s1[i]=='*'||s1[i]=='?') p[++t]=i;
p[++t]=++len;s1[len] = '?';
scanf("%d", &n);
while(n--)
{
scanf("%s", s2+1);Hashtable(s2, 1);
memset(dp, false, sizeof(dp));dp[0][0]=true;
len = strlen(s2+1);s2[++len]='@';
for(int i=0; i <=t-1; i++)
{
if(s1[p[i]]=='*') for(int j=1; j<=len; j++) if(dp[i][j-1]) dp[i][j] = true;
for(int j=0; j<=len; j++)
if(dp[i][j]&&GetHash(j+1,j+(p[i+1]-1)-(p[i]+1)+1,1)==GetHash(p[i]+1, p[i+1]-1, 0))
if(s1[p[i+1]]=='?')
dp[i+1][j+(p[i+1]-1)-(p[i]+1)+1+1]=true;
else
dp[i+1][j+(p[i+1]-1)-(p[i]+1)+1] = true;
}
if(dp[t][len]) puts("YES");
else puts("NO");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: