[CQOI2014]通配符匹配

一、题目

点此看题

弱化版:[AHOI2005]病毒检测

二、解法

先把*当成分割符,这样带通配符的串就被划分成了若干个小串,我们对于每一个小串在去另一个串中匹配。

对于每一个小串,以?为分割符,将它插入 AC \text{AC} 自动机中,标记终止节点,把在小串中的终止位置存在 e d [ x ] ed[x] 中(类型为 v e c t o r vector ),然后我们把一个点在 f a i l fail 树上到根的路径的 e d ed 全部合并到这个点上(方便查询)。匹配另一个串时,对于匹配到的位置 i i ,在自动机上访问到了节点 x x ,我们把 c n t [ i e d [ x ] [ j ] + 1 ] + + cnt[i-ed[x][j]+1]++ ,相当于标记可能的起始位置,匹配完后扫一遍 c n t cnt ,如果某个位置被标记的次数等于插入自动机的段数,那么这个位置就可以作为大的匹配起始点。

本算法的时间复杂度依赖于通配符个数。注意要考虑开始和结束的位置有没有*,需要特殊判断,具体实现可以看代码:

#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");
    }
}
发布了257 篇原创文章 · 获赞 13 · 访问量 6752

猜你喜欢

转载自blog.csdn.net/C202044zxy/article/details/104115899
今日推荐