模糊字符串匹配

模糊字符串匹配

允许有通配符和容错的字符串匹配

定义匹配函数为

\[C(x,y)=a(x)-b(y) \]

当其为0时即完成匹配

完全匹配函数为

\[P(x)=\sum_{i=0}^{m-1}C^2(i,x-m+i+1) \]

平方是为了防止正负抵消

翻转a串得到

\[P(x)=\sum_{i=0}^{m-1}C^2(m-i-1,x-m+i+1) \]

换元展开后得

\[P(x)=\sum_{i=0}^{m-1}(a(i)-b(x-i))^2=\sum_{i=0}^{m-1}a^2(i)+b^2(x-i)-2a_ib_{x-i} \]

分别计算求和即可

若有通配字符则令通配字符的值为0,改P(x)为

\[P(x)=\sum_{i=0}^{m-1}C^2(i,x-i)a(i)b(x-i) \]

展开后为

\[P(x)=\sum_{i=0}^{m-1}a^3(i)b(x-i)-2a^2(i)b^2(x-i)+a(i)b^3(x-i) \]

分别计算三个卷积求和即可

若允许有容错,则分别对每个字符进行统计,每次将该字符标记为1,其余标记为0,然后计算

\[P(x)=P(x)+\sum_{i=0}^{m-1}a(i+x)b(i) \]

翻转b串使其变为b(m-1-i)

其再次变为一个卷积的形式

\[\sum_{i=0}^{m-1}a(i+x)b(m-1-i) \]

求和后即可得到每个位置的匹配数

若同时允许有通配符

对其它字符,每次将模式串中的该字符标记为1,目标串中该字符与通配符标记为1,其余标记为0

对通配字符,将模式串中该字符标记为1,目标串中所有字符标记为1,其余标记为0

仿照上一个求和即可

2021杭电多校第三场1003Problem - 6975 (dingbacode.com)

#include<bits/stdc++.h>
#include<string>
using namespace std;
const int mod=998244353;
int timel;
int g=3,a[3000100],b[3000100],rev[3000100],c[300010]
,d[300010],e[300010],inv1[300010],
l1[300010],l2[300010],gg[300010],ee[300010],ans[300010];
int ksm(int a,int b)
{
    int res=1;
    while(b)
    {
        if(b&1)res=1ll*res*a%mod;
        a=1ll*a*a%mod;
        b>>=1;
    }
    return res;
}
void ntt(int *a,int n,int f)
{
    for(int i=0;i<n;i++)if(i<rev[i])swap(a[i],a[rev[i]]);
    for(int i=1;i<n;i<<=1)
    {
        int gn=ksm(g,(mod-1)/(i<<1));if(f==-1)gn=ksm(gn,mod-2);
        for(int j=0;j<n;j+=i<<1)
        {
            int gqn=1;
            for(int k=j;k<i+j;k++)
            {
                int x=a[k],y=1ll*gqn*a[k+i]%mod;
                a[k]=1ll*(x+y)%mod;
                a[k+i]=1ll*(x-y+mod)%mod;
                gqn=gqn*1ll*gn%mod;
            }
        }
    }
    if(f==-1)
    {
        int ny=ksm(n,mod-2);
        for(int i=0;i<n;i++)a[i]=a[i]*1ll*ny%mod;
    }
}
void inv(int *b,int *e,int n)
{
//    cout<<1;
    if(n==1){e[0]=ksm(b[0],mod-2);return;}
    inv(b,e,(n+1)>>1);
    int bit,len=2;
    for(bit=1;(1<<bit)<(n<<1);bit++)len<<=1;
    for(int i=0;i<n;i++)d[i]=b[i];
    for(int i=n;i<len;i++)
    {
    d[i]=0;
    e[i]=0;
    }
    for(int i=0;i<len;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
    ntt(e,len,1);ntt(d,len,1);
    for (int i=0;i<len;i++)e[i]=(2ll-d[i]*1ll*e[i]%mod+mod)%mod*1ll*e[i]%mod;
    ntt(e,len,-1);
    for(int i=n;i<len;i++)e[i]=0; 
}
void qioudao(int *a,int n)
{
    for(int i=0;i<n;i++)
    a[i]=1ll*a[i+1]*(i+1)%mod;
}
void jifen(int *a,int n)
{
    for(int i=n;i>0;i--)
    a[i]=1ll*a[i-1]*inv1[i]%mod;
    a[0]=0;
}
void nttln(int *a,int n)
{
    for(int i=0;i<n;i++)
    l1[i]=a[i];
    for(int i=0;i<n;i++)
    l2[i]=a[i];
    qioudao(l1,n);
    inv(l2,e,n);
    int bit,len=2;
    for(bit=1;(1<<bit)<(n<<1);bit++)len<<=1;
    for(int i=0;i<n;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
    for(int i=n;i<len;i++)
    l1[i]=0;
    for(int i=n;i<len;i++)
    e[i]=0;
    ntt(l1,len,1);
    ntt(e,len,1);
    for(int i=0;i<len;i++)
    a[i]=1ll*l1[i]*e[i]%mod;
    ntt(a,len,-1);
    jifen(a,n);
}
void exp(int *b,int *ee,int n)
{

    if(n==1){ee[0]=1;return;}
    exp(b,ee,(n+1)>>1);
    for(int i=0;i<n;i++)
    gg[i]=ee[i];
    nttln(gg,n);
    int bit,len=2;
    for(bit=1;(1<<bit)<(n<<1);bit++)len<<=1;
    for(int i=0;i<len;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
    for(int i=0;i<n;i++)
    gg[i]=(b[i]-gg[i]+mod)%mod;
    for(int i=n;i<len;i++)
    {
    gg[i]=0;
    ee[i]=0;
    }
    gg[0]++;
    ntt(ee,len,1);ntt(gg,len,1);
    for (int i=0;i<len;i++)ee[i]=1ll*ee[i]*gg[i]%mod;
    ntt(ee,len,-1);
    for(int i=n;i<len;i++)ee[i]=0; 
}
void kksm(int *a,int k,int n)
{
    nttln(a,n);
    for(int i=0;i<n;i++)
    a[i]=1ll*a[i]*k%mod;
    exp(a,ee,n);
}
string s1,s2;
int sum[1000100];
int tree[200010];
void renew(int x,int k)
{
    for(;x<=200000;x+=(x&(-x)))tree[x]+=k;
}
int cal(int x)
{
    int t=0;
    for(;x;x-=(x&(-x)))t+=tree[x];
//    t+=tree[0];
    return t;
}
int main()
{
//    freopen("std.in","r",stdin);
    inv1[1]=1;
    int bj=0;
    for(int i=2;i<=300000;i++)
    inv1[i]=(mod-mod/i)*1ll*inv1[mod%i]%mod;
    int t;
    cin>>t;
    while(t--)
    {
        int n,m;
        cin>>n>>m;
        cin>>s1>>s2;
        for(int i=0;i<=n;i++)
        {
            ans[i]=0;
            sum[i]=0;
        }
        reverse(s2.begin(),s2.end());
        for(int k='0';k<='9';k++)
        {
            int bit,len=2;
            for(bit=1;(1<<bit)<(n<<1);bit++)len<<=1;
            for(int i=0;i<=n;i++)
            {
                a[i]=0;
                b[i]=0;
            }
            for(int i=0;i<n;i++)
            {
                if(s1[i]==k||s1[i]=='*')a[i]=1;
                else a[i]=0;
            }
            for(int i=n;i<len;i++)a[i]=0;
            for(int i=0;i<m;i++)
            {
                if(s2[i]==k)b[i]=1;
                else b[i]=0;
            }
            for(int i=m;i<len;i++)b[i]=0;
            for(int i=0;i<len;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
            ntt(a,len,1);ntt(b,len,1);
            for(int i=0;i<len;i++)a[i]=1ll*a[i]*b[i]%mod;
            ntt(a,len,-1);
            for(int i=0;i<=n;i++)ans[i]+=a[i];
        }
        
        int bit,len=2;
        for(bit=1;(1<<bit)<(n<<1);bit++)len<<=1;
        for(int i=0;i<=n;i++)
        {
            a[i]=0;
            b[i]=0;
        }
        for(int i=0;i<n;i++)
        {
            a[i]=1;
        }
        for(int i=n;i<len;i++)a[i]=0;
        for(int i=0;i<m;i++)
        {
            if(s2[i]=='*')b[i]=1;
            else b[i]=0;
        }
        for(int i=m;i<len;i++)b[i]=0;
        for(int i=0;i<len;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
        ntt(a,len,1);ntt(b,len,1);
        for(int i=0;i<len;i++)a[i]=1ll*a[i]*b[i]%mod;
        ntt(a,len,-1);
        for(int i=0;i<=n;i++)ans[i]+=a[i];
//        for(int k=0;k<=m;k++)
//        {
//            for(int j=m-1;j<n;j++)
//            {
//                if(ans[j]+k>=m)sum[k]++;
//            }
//            printf("%d\n",sum[k]);
//        }
        for(int j=m-1;j<n;j++)
        {
            int res=m-ans[j];
//            renew(res,1);
            tree[res]++;
        }
        for(int k=0;k<=m;k++)
        {
            if(k)tree[k]+=tree[k-1];
            printf("%d\n",tree[k]);
        }
        memset(tree,0,sizeof(tree));
    }
    return 0;
}
posted @ 2021-07-28 22:00  1427314831a  阅读(396)  评论(0编辑  收藏  举报