模糊字符串匹配
模糊字符串匹配
允许有通配符和容错的字符串匹配
定义匹配函数为
\[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;
}