题面
题意
给出两个字符串,一个模式串,一个匹配串,问匹配串中哪些位置可以匹配上模式串,其中*可以作任意字符。
做法
这个可以转化为多项式,我们可以把*看作0,其他字母看作各个数字,然后发现如果两个字符串相同,当且仅当 ∑ i = 0 n − 1 ( a [ i ] − b [ i ] ) 2 ∗ a [ i ] ∗ b [ i ] = = 0 \sum_{i=0}^{n-1}{(a[i]-b[i])^2*a[i]*b[i]}==0 ∑i=0n−1(a[i]−b[i])2∗a[i]∗b[i]==0成立,因此可以用fft来做。
代码
#include<bits/stdc++.h>
#define db double
#define pi 3.14159265358979
#define eps 0.5
#define N 2100000
using namespace std;
int m,n,l,rev[N];
string str;
struct Xs
{
db ss,xs;
Xs operator + (const Xs &u) const{return (Xs){ss+u.ss,xs+u.xs};}
Xs operator - (const Xs &u) const{return (Xs){ss-u.ss,xs-u.xs};}
Xs operator * (const Xs &u) const{return (Xs){ss*u.ss-xs*u.xs,ss*u.xs+xs*u.ss};}
Xs operator * (const db &u) const{return (Xs){ss*u,xs*u};}
}a[N],b[N],af[N],bf[N],as[N],bs[N],ans[N];
vector<int>an;
inline int zh(char u){return u=='*'?0:u-'a'+1;}
inline void fft(Xs *a,bool dft)
{
int i,j,k;
Xs x,y,dw,now;
for(i=0;i<l;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);
for(i=1;i<l;i<<=1)
{
dw=(Xs){cos(pi/i),sin(pi/i)};
if(!dft) dw.xs*=-1;
for(j=0;j<l;j+=(i<<1))
{
now=(Xs){1,0};
for(k=j;k<i+j;k++)
{
x=a[k];
y=a[k+i]*now;
a[k]=x+y;
a[k+i]=x-y;
now=now*dw;
}
}
}
if(!dft) for(i=0;i<l;i++) a[i].ss/=(db)l;
}
int main()
{
int i,j,t;
cin>>m>>n>>str;
for(i=0;i<m;i++)
{
t=zh(str[i]);
a[i].ss=t;
af[i].ss=t*t;
as[i].ss=t*t*t;
}
cin>>str;
for(i=0;i<n;i++)
{
t=zh(str[i]);
b[i].ss=t;
bf[i].ss=t*t;
bs[i].ss=t*t*t;
}
reverse(b,b+n);
reverse(bf,bf+n);
reverse(bs,bs+n);
for(i=1;i<n;i<<=1);l=(i<<1);
for(i=1;i<l;i++) rev[i]=(rev[i>>1]>>1) | ((i&1)*l/2);
fft(a,1),fft(b,1),fft(af,1),fft(bf,1),fft(as,1),fft(bs,1);
for(i=0;i<l;i++) ans[i]=a[i]*bs[i]+as[i]*b[i]-af[i]*bf[i]*2.0;
fft(ans,0);
reverse(ans,ans+n);
for(i=0;i<n-m+1;i++) if(ans[i].ss<eps) an.push_back(i+1);
cout<<an.size()<<endl;
for(i=0;i<an.size();i++)
{
printf("%d ",an[i]);
}
}