zoukankan      html  css  js  c++  java
  • BZOJ 3507 通配符匹配(贪心+hash或贪心+AC自动机)

    首先可以对n个目标串单独进行处理。

    对于每个目标串,考虑把模式串按'*'进行划分为cnt段。首尾两段一定得于原串进行匹配。剩下的cnt-2段尽量与最靠左的起点进行匹配。

    对于剩下的cnt-2段。每段又可以通过‘?’划分为k个子串。对每个子串求出hash值。然后通过枚举起点与目标串的某个区间的hash进行判断。

    就可以在O(k)的时间进行每一次的枚举了。对于目标串区间的hash值。可以通过预处理hash前缀进行O(1)询问。

    而最多进行len次枚举。所以总复杂度为O(n*len*k).

    另外判断子串匹配目标串的区间用AC自动机也是可以的。

    # include <cstdio>
    # include <cstring>
    # include <cstdlib>
    # include <iostream>
    # include <vector>
    # include <queue>
    # include <stack>
    # include <map>
    # include <set>
    # include <cmath>
    # include <algorithm>
    using namespace std;
    # define lowbit(x) ((x)&(-x))
    # define pi 3.1415926535
    # define eps 1e-4
    # define MOD 1000000007
    # define INF 1000000000
    # define mem(a,b) memset(a,b,sizeof(a))
    # define FOR(i,a,n) for(int i=a; i<=n; ++i)
    # define FO(i,a,n) for(int i=a; i<n; ++i)
    # define bug puts("H");
    # define lch p<<1,l,mid
    # define rch p<<1|1,mid+1,r
    # define mp make_pair
    # define pb push_back
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    # pragma comment(linker, "/STACK:1024000000,1024000000")
    typedef long long LL;
    inline int Scan() {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    void Out(int a) {
        if(a<0) {putchar('-'); a=-a;}
        if(a>=10) Out(a/10);
        putchar(a%10+'0');
    }
    const int N=100010;
    //Code begin...
    
    char str[N], ss[N];
    int hs[N], shs[N], xing[55], pos, bg, ed;
    struct Node{int x, len; bool flag;}node[55];
    
    int get_hash(int l, int r){return shs[r]-shs[l-1]*hs[r-l+1];}
    bool check(int be, int L){
        int sum=0;
        FOR(i,1,L) if (node[i].flag) sum+=node[i].x; else sum+=node[i].len;
        if (be+sum>ed+1) return false;
        FOR(i,1,L) {
            if (node[i].flag) be+=node[i].x;
            else {
                if (get_hash(be,be+node[i].len-1)!=node[i].x) return false;
                be+=node[i].len;
            }
        }
        return true;
    }
    bool sol(){
        int num, sum, l, cnt, ll;
        FOR(i,2,pos) {
            if (xing[i]-xing[i-1]<=1) continue;
            sum=num=l=ll=cnt=0;
            FOR(j,xing[i-1]+1,xing[i]-1) {
                if (str[j]=='?') {
                    ++num;
                    if (l) node[++cnt].x=sum, node[cnt].len=l; node[cnt].flag=0, sum=l=0;
                }
                else {
                    sum=sum*MOD+str[j]; ++l;
                    if (num) node[++cnt].x=num, node[cnt].flag=1, num=0;
                }
            }
            if (l) node[++cnt].x=sum, node[cnt].len=l; node[cnt].flag=0, sum=l=0;
            if (num) node[++cnt].x=num, node[cnt].flag=1, num=0;
            while (bg<=ed&&!check(bg,cnt)) ++bg;
            if (!check(bg,cnt)) return false;
            FOR(i,1,cnt) if (node[i].flag) ll+=node[i].x; else ll+=node[i].len;
            bg+=ll;
        }
        return true;
    }
    int main ()
    {
        hs[0]=1; FO(i,1,N) hs[i]=hs[i-1]*MOD;
        scanf("%s",str+1);
        int T;
        scanf("%d",&T);
        while (T--) {
            scanf("%s",ss+1);
            pos=0; bg=1; ed=strlen(ss+1);
            for (int i=1; ss[i]; ++i) shs[i]=shs[i-1]*MOD+ss[i];
            int l=1, r=strlen(str+1);
            int flag=0;
            while (str[l]!='*'&&l<=r&&bg<=ed) {
                if (str[l]=='?'||str[l]==ss[bg]) ++l, ++bg;
                else {flag=1; break;}
            }
            while (str[r]!='*'&&l<=r&&bg<=ed) {
                if (str[r]=='?'||str[r]==ss[ed]) --r, --ed;
                else {flag=1; break;}
            }
            if (flag) {puts("NO"); continue;}
            FOR(i,l,r) if (str[i]=='*') xing[++pos]=i;
            if (pos==0&&bg<=ed) {puts("NO"); continue;}
            puts(sol()?"YES":"NO");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    C语言中do...while(0)用法小结
    C语言函数指针的用法
    C语言预处理命令之条件编译
    欧拉计划11-15题
    欧拉计划6-10题
    已加载“C:WindowsSysWOW64 tdll.dll”。无法查找或打开 PDB 文件。
    C++使用SQLite步骤及示例
    linux 安装sysstat使用iostat、mpstat、sar、sa
    Nmon命令行:Linux系统性能的监测利器
    linux服务器性能检测工具nmon使用
  • 原文地址:https://www.cnblogs.com/lishiyao/p/6708677.html
Copyright © 2011-2022 走看看