题面描述:S、T两个串,求出T在S中出现了几次。其中T中有'?'可以匹配任意字符。S长度n不超过10^5,T长度m不超过S长度。
乍一看因该是个关于字符串处理的题目,然后我就杯具了。。。。
果断滚粗去看题解,这居然是到FFT!
先把T字符串翻转,定义 c[j+m-1] = sigma( (a[j+i]-b[m-1-i])^2 * a[j+i] * b[m-1-i] )(0<=i<m)
其中定义 字符’?‘的值为0,'a'~’z'为1~26,a为S的权值数组,b为T的权值数组。
那么如果c[j+m-1]=0,那么S[j~j+m-1]与T匹配,否则不匹配。
直接求c数组复杂度是O(nm),如何快速求c数组?
将式子展开得 c[j+m-1] = sigma( a[j+i]^3*b[m-1-i] ) + sigma( a[j+i]*b[m-1-i]^3 ) - 2*sigma( a[j+i]^2*b[m-1-i]^2 )
每一个可以发现这其实是个卷积,对于每个Sigma里用FFT求一下即可,复杂度O(nlogn)
(蒟蒻被虐得爽爽的)
//吐槽:stl里的complex确实好慢。。。老老实实的手写去了
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int Maxn=400005;
#define sqr(a) ((a)*(a))
#define cube(a) ((a)*(a)*(a))
typedef long long LL;
int n,m,N,M,i,j,k,cnt,rev[Maxn],dig[20];
LL ans[Maxn];
char S[Maxn],T[Maxn];
struct CP
{
double X,Y;
CP operator +(const CP &a){ return (CP){X+a.X,Y+a.Y}; }
CP operator -(const CP &a){ return (CP){X-a.X,Y-a.Y}; }
CP operator *(const CP &a){ return (CP){X*a.X-Y*a.Y,X*a.Y+Y*a.X}; }
} a[Maxn],b[Maxn];
void FFT(CP a[],int flag){
for (i=0;i<N;i++)
if (i<rev[i]) swap(a[i],a[rev[i]]);
for (i=2;i<=N;i<<=1){
CP wn = (CP) { cos(2*M_PI/i), flag*sin(2*M_PI/i) };
for (j=0;j<N;j+=i){
CP w = (CP) {1,0};
for (k=j;k<j+i/2;k++){
CP x=a[k], y=a[k+i/2]*w;
a[k]=x+y; a[k+i/2]=x-y; w=w*wn;
}
}
}
if (flag==1) return;
for (i=0;i<N;i++) a[i].X/=N;
}
void calc(LL flag){
FFT(a,1); FFT(b,1);
for (i=0;i<N;i++) a[i]=a[i]*b[i];
FFT(a,-1);
for (i=m-1;i<m-1+n;i++)
ans[i-m+1]+=flag * (LL) (a[i].X+0.5);
}
int main(){
freopen("match.in","r",stdin);
freopen("match.out","w",stdout);
scanf("%s",S); n=strlen(S);
scanf("%s",T); m=strlen(T);
for (i=0;i+i<m-1;i++)
swap(T[i],T[m-1-i]);
for (N=2, M=1;N<(n+m);N<<=1, M++);
for (i=0;i<N;i++){
int len=0;
for (j=i;j>0;j>>=1) dig[len++]=(j&1);
for (j=0;j<M;j++) rev[i]=( (rev[i]<<1)|dig[j] );
}
// a^3*b
for (i=0;i<n;i++)
{a[i]=(CP){S[i]!='?'?S[i]-'a'+1:0, 0}; a[i].X=cube(a[i].X);}
for (i=n;i<N;i++) a[i]=(CP){0,0};
for (i=0;i<m;i++) b[i]=(CP){ T[i]!='?'?T[i]-'a'+1:0, 0};
for (i=m;i<N;i++) b[i]=(CP){0,0};
calc(1);
//a*b^3
for (i=0;i<n;i++) a[i]=(CP){S[i]!='?'?S[i]-'a'+1:0, 0};;
for (i=n;i<N;i++) a[i]=(CP){0,0};
for (i=0;i<m;i++)
{b[i]=(CP){ T[i]!='?'?T[i]-'a'+1:0, 0}; b[i].X=cube(b[i].X);}
for (i=m;i<N;i++) b[i]=(CP){0,0};
calc(1);
//a^2*b^2
for (i=0;i<n;i++)
{a[i]=(CP){S[i]!='?'?S[i]-'a'+1:0, 0};; a[i].X=sqr(a[i].X);}
for (i=n;i<N;i++) a[i]=(CP){0,0};
for (i=0;i<m;i++)
{b[i]=(CP){ T[i]!='?'?T[i]-'a'+1:0, 0}; b[i].X=sqr(b[i].X);}
for (i=m;i<N;i++) b[i]=(CP){0,0};
calc(-2);
for (i=0;i<=n-m;i++)
if (ans[i]==0) cnt++;
printf("%d\n",cnt);
for (i=0;i<=n-m;i++)
if (ans[i]==0) printf("%d\n",i);
return 0;
}