• 【BZOJ-3507】通配符匹配 DP + Hash


    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

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    #define ULL unsigned long long
    #define MAXN 100010
    #define BASE 131
    char S[MAXN],s[MAXN];
    ULL hash[2][MAXN],bin[MAXN];
    int p[20],t,N;
    bool f[12][MAXN];
    inline 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];
    }
    inline ULL GetHash(int l,int r,int opt)
    {
        return r>l? hash[opt][r]-hash[opt][l-1]*bin[r-l+1] : -1;
    }
    int main()
    {
        bin[0]=1; for (int i=1; i<=MAXN-1; i++) bin[i]=bin[i-1]*BASE;
        scanf("%s",S+1); Hashtable(S,0);
        int len=strlen(S+1);
        for (int i=1; i<=len; i++) if (S[i]=='*' || S[i]=='?') p[++t]=i;
        p[++t]=++len; S[len]='?';
    //    for (int i=1; i<=t; i++) printf("%d   %c
    ",p[i],S[p[i]]);
        scanf("%d",&N);
        while (N--)
            {
                scanf("%s",s+1); Hashtable(s,1);
                memset(f,0,sizeof(f)); f[0][0]=1;
                int len=strlen(s+1); s[++len]='@';
                for (int i=0; i<=t-1; i++)
                    {
                        if (S[p[i]]=='*') for (int j=1; j<=len; j++) if (f[i][j-1]) f[i][j]=1;
                        for (int j=0; j<=len; j++)
                            if (f[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 (S[p[i+1]]=='?') f[i+1][j+(p[i+1]-1)-(p[i]+1)+1+1]=1; else f[i+1][j+(p[i+1]-1)-(p[i]+1)+1]=1;
                    }
                if (f[t][len]) puts("YES"); else puts("NO");
            }
        return 0;
    }
  • 相关阅读:
    【转载】[教程]OpenSEES超简单易懂的入门第一课
    【转载】面向对象的非线性有限元方法
    与李文雄老师讨论有限元
    【转载】 Moving Beyond OpenGL 1.1 for Windows
    【转载】国外免费期刊全文数据库
    与李文雄老师讨论学术研究
    【转载】VS 2010和.NET 4.0之WPF 4改进全解析
    【转载】MFC中SDI、MDI框架各部分指针获取(网上找的,好东西大家一起分享,多谢原创作者!)
    【转载】一位院士——搞科研的几个条件
    Visual Studio 2010 step by step学习摘要
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5962702.html
Copyright © 2020-2023  润新知