zoukankan      html  css  js  c++  java
  • [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
  • 相关阅读:
    POJ 1887 Testing the CATCHER
    HDU 3374 String Problem
    HDU 2609 How many
    POJ 1509 Glass Beads
    POJ 1458 Common Subsequence
    POJ 1159 Palindrome
    POJ 1056 IMMEDIATE DECODABILITY
    POJ 3080 Blue Jeans
    POJ 1200 Crazy Search
    软件体系结构的艺术阅读笔记1
  • 原文地址:https://www.cnblogs.com/LadyLex/p/7044684.html
Copyright © 2011-2022 走看看