[BZOJ3507]通配符匹配
3507: [Cqoi2014]通配符匹配
Time Limit: 10 Sec Memory Limit: 128 MBDescription
几乎所有操作系统的命令行界面(CLI)中都支持文件名的通配符匹配以方便用户。最常见的通配符有两个,一个
是星号(“”’),可以匹配0个及以上的任意字符:另一个是问号(“?”),可以匹配恰好一个任意字符。
现在需要你编写一个程序,对于给定的文件名列表和一个包含通配符的字符串,判断哪些文件可以被匹配。
Input
第一行是一个由小写字母和上述通配符组成的字符串。
第二行包含一个整数n,表示文件个数。
接下来n行,每行为一个仅包含小写字母字符串,表示文件名列表。
Output
输出n行,每行为“YES”或“NO”,表示对应文件能否被通配符匹配。
Sample Input
*aca?ctc
6
acaacatctc
acatctc
aacacatctc
aggggcaacacctc
aggggcaacatctc
aggggcaacctct
6
acaacatctc
acatctc
aacacatctc
aggggcaacacctc
aggggcaacatctc
aggggcaacctct
Sample Output
YES
YES
YES
YES
YES
NO
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\n"); 69 else printf("NO\n"); 70 } 71 }
Progress is not created by contented people.