题目链接
题意
给你一篇由小写字母组成的文章,再给你一系列查询。
每次查询给你一系列由小写字母和_
组成的字符串,_
是要填空的区域,问能否根据文章填空,即填空后找到原文。
思路
将每个字符串转化为一个hash值,然后对要查找串的一系列hash值,在原文中用kmp查找,_
转化为一个无冲突的hash值,比如
−
1
-1
−1,kmp和求nxt数组时将
−
1
-1
−1设为万能匹配即可。匹配成功即能填空
代码
#include <stdio.h>
#include <string.h>
using namespace std;
int Rd(int &a){return scanf("%d",&a);}
int rd(){int tmp; scanf("%d",&tmp); return tmp;}
int fq[1005], want[1005], nxt[1005];
char s[1005];
void getnxt(int len)
{
nxt[1] = 0;
int i = 1, j = 0;
while(i <= len)
{
if(j == 0 || want[i] == want[j] || want[i] == -1 || want[j] == -1) nxt[++i] = ++j;
else j = nxt[j];
}
}
int kmp(int n, int m)
{
int i = 1, j = 1;
while(i <= n)
{
if(j == 0 || fq[i] == want[j] || want[j] == -1) ++i, ++j;
else j = nxt[j];
if(j == m+1) return 1;
}
return 0;
}
int main()
{
for(int t = rd(), ca = 1; ca <= t; ++ca)
{
int tot = 0;
while(scanf("%s",s), s[0] != '@')
{
int len = strlen(s);
int tmp = 0;
for(int i = 0; i < len; ++i)
{
tmp += s[i]-'a';
tmp *= 26;
}
fq[++tot] = tmp;
}
int m = rd();
printf("Case %d:\n",ca);
while(m--)
{
int ind = 0;
while(scanf("%s",s), s[0] != '@')
{
if(s[0] == '_')
{
want[++ind] = -1;
continue;
}
int len = strlen(s);
int tmp = 0;
for(int i = 0; i < len; ++i)
{
tmp += s[i]-'a';
tmp *= 26;
}
want[++ind] = tmp;
}
getnxt(ind);
printf("%s\n",kmp(tot,ind)?"YES":"NO");
}
}
return 0;
}