【BZOJ4259】残缺的字符串(FFT)

【BZOJ4259】残缺的字符串(FFT)

题面

给定两个字符串\(|S|,|T|\),两个字符串中都带有通配符。

回答\(T\)\(S\)中出现的次数。

\(|T|,|S|<=300000\)

题解

两个串基本一样。。

现在\(S\)串中也存在通配符,所以在函数后面再额外乘上一个\(S[i]\)就行了。

拆开式子后是三个卷积的形式。

时间复杂度\(O(nlogn)\)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 888888
const double Pi=acos(-1);
struct Complex{double a,b;}A1[MAX],B1[MAX],A2[MAX],B2[MAX],A3[MAX],B3[MAX],W[MAX],F[MAX];
Complex operator+(Complex a,Complex b){return (Complex){a.a+b.a,a.b+b.b};}
Complex operator-(Complex a,Complex b){return (Complex){a.a-b.a,a.b-b.b};}
Complex operator*(Complex a,Complex b){return (Complex){a.a*b.a-a.b*b.b,a.a*b.b+a.b*b.a};}
int n,m,r[MAX],N,Z;
int pos[MAX],ans,l;
char S[MAX],T[MAX];
void FFT(Complex *P,int opt)
{
	for(int i=1;i<N;++i)if(i<r[i])swap(P[i],P[r[i]]);
	for(int i=1;i<N;i<<=1)
		for(int p=i<<1,j=0;j<N;j+=p)
			for(int k=0;k<i;++k)
			{
				Complex w=(Complex){W[N/i*k].a,W[N/i*k].b*opt};
				Complex X=P[j+k],Y=w*P[j+k+i];
				P[j+k]=X+Y;P[i+j+k]=X-Y;
			}
	if(opt==-1)for(int i=0;i<N;++i)P[i].a/=N;
}
int main()
{
	scanf("%d%d",&m,&n);
	scanf("%s",T);scanf("%s",S);
	for(N=1;N<=(n+m-2);N<<=1)++l;
	for(int i=0;i<N;++i)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
	for(int i=1;i<N;i<<=1)
		for(int k=0;k<i;++k)W[N/i*k]=(Complex){cos(k*Pi/i),sin(k*Pi/i)};
	for(int i=0;i<n;++i)
	{
		int x=((S[i]=='*')?0:(S[i]-96));
		A1[i].a=x,A2[i].a=2*x*x,A3[i].a=x*x*x;
	}
	for(int i=0;i<m;++i)
	{
		int x=((T[m-i-1]=='*')?0:(T[m-i-1]-96));
		B1[i].a=x,B2[i].a=x*x,B3[i].a=x*x*x;
	}
	FFT(A1,1);FFT(B1,1);FFT(A2,1);FFT(B2,1);FFT(A3,1);FFT(B3,1);
	for(int i=0;i<N;++i)
		F[i]=A1[i]*B3[i]-A2[i]*B2[i]+A3[i]*B1[i];
	FFT(F,-1);
	for(int i=m-1;i<n;++i)
		if((int)(F[i].a+0.5)==0)pos[++ans]=i-m+1;
	printf("%d\n",ans);
	for(int i=1;i<=ans;++i)printf("%d ",pos[i]+1);puts("");
	return 0;
}

posted @ 2018-04-11 20:22  小蒟蒻yyb  阅读(360)  评论(0编辑  收藏  举报