UOJ Logo zhouzixuan的博客

博客

bzoj 3507: [Cqoi2014]通配符匹配

2016-02-13 23:32:15 By zhouzixuan
【题目描述】:
    几乎所有操作系统的命令行界面(CLI)中都支持文件名的通配符匹配以方便用户。最常见的通配符有两个,一个是星号(“”’),可以匹配0个及以上的任意字符:另一个是问号(“?”),可以匹配恰好一个任意字符。
    现在需要你编写一个程序,对于给定的文件名列表和一个包含通配符的字符串,判断哪些文件可以被匹配。
    字符串长度不超过100000
    1<=n<=100
    通配符个数不超过10
【题目描述】:
    《感觉复杂度不对系列》
    我们考虑一个一个的去匹配
    考虑动态规划,我们用f[i][j]表示模板串前i个和匹配串前j的是否可以匹配,根据对应字符匹配即可
    然后这样做的复杂度是O(|S|^2),显然会MLE+TLE
    我们考虑对于不包含通配符的模板串,我们直接KMP一下,然后DP转移即可
    即:如果模板串在匹配串中成功匹配的起点为i,长度为len,那么f[next][i+len-1]|=f[cur][i]
    然后我们考虑对于'?',显然f[next][i]|=f[cur][i-1]
    对于'*',我们找到第一个f[cur][i]为true的,然后将f[next][i...n]全部变成true
    考虑这样做的复杂度,这样做相当于把不含通配符的一段当成一个字符来处理,由于最多只有10个通配符,那么压缩后的字符串长度不超过20
    因此复杂度就是O(|S|*20),|S|=100000
    恩恩,看起来很靠谱滴样子,等等外面还有个N=100
    时间复杂度O(N*|S|*20) TAT
    不管了,写一发,然后A了不科学啊TAT
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=100005;
int n,m,lena,lenb; bool f[2][N];
char s[N],a[N],b[N]; int p[N],cnt,pos[N];
inline long long getint()
{
    long long x=0; char c=getchar(); bool flag=false;
    while ((c!='-')&&((c<'0')||(c>'9'))) c=getchar();
    if (c=='-') flag=true,c=getchar();
    while ((c>='0')&&(c<='9')) x=x*10+(long long)(c-'0'),c=getchar();
    if (flag) return -x; else return x;
}
void init()
{
    scanf("%s",s+1); n=strlen(s+1);
}
inline void KMP()
{
    cnt=0; p[1]=0;
    for (int i=2,j=0; i<=lena; i++)
    {
        for (;(j>0)&&(a[i]!=a[j+1]);j=p[j]);
        if (a[i]==a[j+1]) j++; p[i]=j;
    }
    for (int i=1,j=0; i<=lenb; i++)
    {
        for (;(j>0)&&(b[i]!=a[j+1]);j=p[j]);
        if (b[i]==a[j+1]) j++;
        if (j==lena) pos[++cnt]=i-lena+1,j=p[j];
    }
}
bool judge()
{
    memset(f,false,sizeof(f));
    int cur=0,next=1; f[cur][0]=true;
    for (int i=1,j=0; i<=n; i=j,swap(cur,next))
    {
        memset(f[next],false,sizeof(f[next]));
        if (s[i]=='*')
        {
            for (j=0; j<=lenb; j++) if (f[cur][j]) break;
            if (j==lenb+1) {j=i+1; continue;}
            for (int k=j; k<=lenb; k++) f[next][k]=true;
            j=i+1; continue;
        }
        if (s[i]=='?')
        {
            for (int k=0; k<=lenb-1; k++) f[next][k+1]|=f[cur][k];
            j=i+1; continue;
        }
        for (j=i,lena=0; (j<=n)&&(s[j]!='*')&&(s[j]!='?'); j++) a[++lena]=s[j]; KMP();
        for (int k=1; k<=cnt; k++) f[next][pos[k]+lena-1]|=f[cur][pos[k]-1];
    }
    return f[cur][lenb];
}
void solve()
{
    m=getint();
    for (int i=1; i<=m; i++)
    {
        scanf("%s",b+1); lenb=strlen(b+1);
        if (judge()) printf("YES\n"); else printf("NO\n");
    }
}
int main()
{
    init();
    solve();
    return 0;
}

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。