众所周知多校签到题中必有一道板子题,那么只要会使用板子就可以多做出一道签到了.
本题就是一道FFT的板子题.
题意
给出长度为 n n n的字符串 s s s,长度为 m m m的字符串 t t t,定义两字符串匹配是两个字符串对应不相等的位置数量不超过 k k k,其中通配符 ∗ * ∗能匹配任何一个字符.对 k ∈ [ 0 , m ] k\in[0,m] k∈[0,m]的每一个值输出 t t t在 s s s中能匹配的位置的数量.
题解
我们需要将
t
t
t在每一个位置不能匹配上的个数加入
c
n
t
cnt
cnt数组然后对其求一遍前缀和便能够得到答案.
对
c
h
∈
[
"
0123456789
∗
"
]
ch\in["0123456789*"]
ch∈["0123456789∗"]这
11
11
11个字符分别做一遍
f
f
t
fft
fft,具体是令
a
i
a_i
ai表示
s
i
s_i
si是否等于
c
h
ch
ch,令
b
i
b_i
bi表示
t
m
−
i
+
1
t_{m-i+1}
tm−i+1是否等于
c
h
ch
ch,然后
a
×
b
a\times b
a×b进行卷积即可,注意通配符可以匹配任何一个字符,所以特地把通配符拿出来做一次卷积,然后把乘出来为
1
1
1的部分减掉(两个都是通配符就重复计算了一次).最后单独加上两个字符串中通配符的贡献即可.
代码如下.
#include<bits/stdc++.h> //Ithea Myse Valgulious
typedef long long ll;
using namespace std;
const int yuzu=1<<20;
using db=double;
const db pi=3.14159265358979;
typedef int fuko[yuzu];
typedef char fuka[yuzu];
struct cpx {
db x,y;
cpx(db x,db y):x(x),y(y) {}
cpx(db x=0):x(x),y(0) {}
cpx operator +(const cpx &b) {
return cpx(x+b.x,y+b.y);
}
cpx operator -(const cpx &b) {
return cpx(x-b.x,y-b.y);
}
cpx operator *(const cpx &b) {
return cpx(x*b.x-y*b.y,x*b.y+y*b.x);
}
cpx operator *(int o) {
return cpx(x*o,y*o);
}
}a[yuzu],b[yuzu],ans[yuzu];
fuko rv,cnts,zw;
void fft(cpx *a,int n,int rev) {
for (int i=0;i<n;++i)
if (i<rv[i]) swap(a[i],a[rv[i]]);
for (int len=2;len<=n;len<<=1) {
cpx now(cos(2*pi/len),sin(2*pi*rev/len));
for (int st=0;st<n;st+=len) {
cpx fl(1,0);
for (int pos=st;pos<st+(len>>1);++pos) {
cpx tmp=fl*a[pos+(len>>1)];
a[pos+(len>>1)]=a[pos]-tmp;
a[pos]=a[pos]+tmp;
fl=fl*now;
}
}
}
}
fuka s,t;
int main() {
int i,ca,n,m;
for (scanf("%d",&ca);ca--;) {
scanf("%d%d%s%s",&n,&m,s,t);
memset(zw,0,sizeof zw);
memset(cnts,0,sizeof cnts);
for (i=0;i<n;++i) {
i?cnts[i]+=cnts[i-1]:0;
cnts[i]+=s[i]=='*';
}
int cntt=0,len=1; for (;len<n+m;len<<=1);
for (i=0;i<m;++i) cntt+=t[i]=='*';
reverse(t,t+m);
for (i=0;i<len;++i) ans[i]=0,rv[i]=(rv[i>>1]>>1)|(i&1?len>>1:0);
for (char ch:"0123456789*") {
for (i=0;i<n;++i) a[i]=s[i]==ch;
for (i=n;i<len;++i) a[i]=0;
for (i=0;i<m;++i) b[i]=t[i]==ch;
for (i=m;i<len;++i) b[i]=0;
fft(a,len,1),fft(b,len,1);
for (i=0;i<len;++i) ans[i]=ans[i]+a[i]*b[i]*(ch^'*'?1:-1);
}
fft(ans,len,-1);
for (i=0;i<len;++i) ans[i].x/=len;
for (i=m-1;i<n;++i) {
++zw[m-int(ans[i].x+(i==m-1?cnts[i]:cnts[i]-cnts[i-m])+cntt+.5)];
}
for (i=0;i<=m;++i) {
i?zw[i]+=zw[i-1]:0;
printf("%d\n",zw[i]);
}
}
}
谢谢大家.