一、题目
弱化版:[AHOI2005]病毒检测
二、解法
先把*
当成分割符,这样带通配符的串就被划分成了若干个小串,我们对于每一个小串在去另一个串中匹配。
对于每一个小串,以?
为分割符,将它插入
自动机中,标记终止节点,把在小串中的终止位置存在
中(类型为
),然后我们把一个点在
树上到根的路径的
全部合并到这个点上(方便查询)。匹配另一个串时,对于匹配到的位置
,在自动机上访问到了节点
,我们把
,相当于标记可能的起始位置,匹配完后扫一遍
,如果某个位置被标记的次数等于插入自动机的段数,那么这个位置就可以作为大的匹配起始点。
本算法的时间复杂度依赖于通配符个数。注意要考虑开始和结束的位置有没有*
,需要特殊判断,具体实现可以看代码:
#include <cstdio>
#include <vector>
#include <cstring>
#include <queue>
using namespace std;
const int M = 100005;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int T,n,m,Beg,End;
char s[M],t[M];
struct automaton
{
vector<int> ed[M];
int tot,last,cnt[M],fail[M],c[M][26];
int newnode()
{
fail[tot]=0;ed[tot].clear();
for(int i=0;i<26;i++) c[tot][i]=0;
return tot++;
}
void ins(int l,int r,int id)
{
int now=0;
for(int i=l;i<=r;i++)
{
int v=t[i]-'a';
if(!c[now][v]) c[now][v]=newnode();
now=c[now][v];
}
ed[now].push_back(id);
}
void build()
{
queue<int> q;
for(int i=0;i<26;i++) if(c[0][i]) q.push(c[0][i]);
while(!q.empty())
{
int t=q.front();
q.pop();
for(int i=0;i<ed[fail[t]].size();i++)
ed[t].push_back(ed[fail[t]][i]);
for(int i=0;i<26;i++)
if(c[t][i]) fail[c[t][i]]=c[fail[t]][i],q.push(c[t][i]);
else c[t][i]=c[fail[t]][i];
}
}
int find(int l,int r,bool f,bool e)
{
tot=0;newnode();
memset(cnt,0,sizeof cnt);
int seg=0;
for(int i=l;i<=r;i++)
if(t[i]^'?')
{
int pos=i;
while(pos<=r && t[pos]!='?') pos++;pos--;
ins(i,pos,pos-l+1);
i=pos;seg++;
}
build();
for(int i=1,now=0;i<=n;i++)
{
int v=s[i]-'a';
now=c[now][v];
for(int j=0;j<ed[now].size();j++)
if(i-ed[now][j]+1>0)
cnt[i-ed[now][j]+1]++;
}
for(int i=1;i<=n;i++)
if(cnt[i]==seg)
{
if(i<=last) continue;
if(!Beg && f && i!=1) continue;
if(!End && e && i+r-l!=n) continue;
last=i+r-l;
return 1;
}
return 0;
}
}AC;
int main()
{
scanf("%s",t+1);m=strlen(t+1);
Beg=(t[1]=='*');End=(t[m]=='*');
while(t[m]=='*') m--;
T=read();
while(T--)
{
AC.last=0;//
scanf("%s",s+1);n=strlen(s+1);
int pos=0,flag=0,pd=1;
for(int i=1;i<=m;i++)
if(t[i]^'*')
{
pos=i;
while(pos<=m && t[pos]^'*') pos++;pos--;
if(!AC.find(i,pos,pd,pos==m)) {flag=1;break;}
i=pos;pd=0;
}
if(!flag) puts("YES");
else puts("NO");
}
}