• [BZOJ3507]通配符匹配


    3507: [Cqoi2014]通配符匹配

    Time Limit: 10 Sec  Memory Limit: 128 MB

    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

    题解:

    考场打暴力打炸了……

    不过在后来改题的时候我发现了暴力思路的一个大问题……我们还是直接讲正解吧

    题目给的通配符有2种,一种是’*’,它可以伸展;一种是‘?’,它的长度固定;

    不难发现,给我们的处理带来难度的是'*',因为他的长度不确定;

    但转念一想,如果除了*,其他的都能匹配,那*也就能匹配了.

    注意到通配符个数<=10,那么我们可以先按照*,把原串分成一些包含'?'和字母的段.

    而对于每一段,只要其中的所有小字符串成功匹配,并且符合'?'对长度的要求,这一段就匹配成功了

    所以我们再在每一段里,按照'?'再分为几小块只含字母的串,并且分别求出hash值;同时求出文本串的hash值.

    在匹配的时候,对于某一段,枚举起点,看在这一段在哪里可以匹配.

    由于对于段间的枚举,影响因素只有*,所以匹配点肯定越靠前越好,因此这里可以贪心,即找到最靠前的匹配点即可停止.

    而对于段内比较,利用刚才求的hash值比较就好.

    代码见下:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #include<string>
     5 using namespace std;
     6 typedef unsigned long long LL;
     7 const int N=100010;
     8 const int mod1=9901;
     9 int n,lens,len,cnt,cnt1[20];
    10 char s[N],text[N];
    11 LL block[20][20],h[N],mi[N];
    12 int l[20][20],num[20];
    13 inline LL g_hash(int l,int r){return h[r]-h[l-1]*mi[r-l+1];}
    14 inline bool match(int i,int k)
    15 {
    16     for(int j=0;j<=num[k];j++)
    17     {
    18         if(l[k][j]==0){i++;continue;}
    19         if(block[k][j]!=g_hash(i,i+l[k][j]-1))return 0;
    20         i+=l[k][j]+1;
    21     }
    22     return 1;
    23 }
    24 bool judge()
    25 {
    26     if(!cnt)
    27     {
    28         if(len!=lens)return 0;
    29         for(int i=1;i<=len;i++)
    30             if(s[i]!=text[i]&&s[i]!='?')return 0;
    31         return 1;
    32     }
    33     if(len<(cnt1[1]-1)+(lens-cnt1[cnt]))return 0;
    34     for(int i=1;i<cnt1[1];i++)if(s[i]!=text[i]&&s[i]!='?')return 0;
    35     for(int i=lens,j=len;i>cnt1[cnt];i--,j--)if(s[i]!=text[j]&&s[i]!='?')return 0;
    36     for(int i=1;i<=len;i++)
    37         h[i]=h[i-1]*mod1+text[i];
    38     int i=cnt1[1],line=len-(lens-cnt1[cnt])+1;
    39     for(int k=2;k<=cnt;k++)
    40     {
    41         for(;i<=line;i++)
    42             if(match(i,k))break;
    43         i+=cnt1[k]-cnt1[k-1]-1;
    44         if(i>line)return 0;
    45     }
    46     return 1;
    47 }
    48 int main()
    49 {
    50     scanf("%s",s+1);lens=strlen(s+1);
    51     mi[0]=1;for(int i=1;i<=lens;i++)mi[i]=mi[i-1]*mod1;
    52     for(int i=1;i<=lens;i++)
    53         if(s[i]=='*')cnt1[++cnt]=i;
    54     for(int i=2;i<=cnt;i++)
    55     {
    56         num[i]=0;
    57         for(int j=cnt1[i-1]+1;j<cnt1[i];j++)
    58         {
    59             if(s[j]=='?'){num[i]++;continue;}
    60             l[i][num[i]]++;
    61             block[i][num[i]]=block[i][num[i]]*mod1+s[j];
    62         }
    63     }
    64     scanf("%d",&n);
    65     for(int i=1;i<=n;i++)
    66     {
    67         scanf("%s",text+1);len=strlen(text+1);
    68         if(judge())printf("YES
    ");
    69         else printf("NO
    ");
    70     }
    71 }
    BZOJ3507
  • 相关阅读:
    解决vs 编译的bug“请检查是否是磁盘空间不足、路径无效或权限不够”
    lua 使用正则表达式分割字符串
    cocos2dx通过ndk编译c++库
    通过luac编译lua脚本
    redis的一个bug
    将文件转成16进制过程
    fiddler 模拟发送post请求
    cocostudio的bug(1)
    Eclipse+Tomcat搭建jsp服务器
    iOS本地推送与远程推送
  • 原文地址:https://www.cnblogs.com/LadyLex/p/7044684.html
Copyright © 2020-2023  润新知