[BZOJ4503]两个串

$\newcommand{align}[1]{\begin{align*}#1\end{align*}}$如果$S_{i\cdots i+m-1}$与$T$相等,那么$\align{\sum\limits_{j=0}^{m-1}\left(S_{i+j}-T_j\right)^2T_j}=0$(令通配符为$T_i=0$),展开得到$\align{\sum\limits_{j=0}^{m-1}S^2_{i+j}T_j-2\sum\limits_{j=0}^{m-1}S_{i+j}T^2_j+\sum\limits_{j=0}^{m-1}T_j^3}$,这种错位相乘直接翻转卷积即可

这大概是一个套路...学习之

#include<stdio.h>
#include<math.h>
#include<string.h>
typedef double du;
const du eps=1e-5;
struct complex{
	du x,y;
	complex(du a=0,du b=0){x=a;y=b;}
};
complex operator+(complex a,complex b){return complex(a.x+b.x,a.y+b.y);}
complex operator-(complex a,complex b){return complex(a.x-b.x,a.y-b.y);}
complex operator*(complex a,complex b){return complex(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
template<class T>void swap(T&a,T&b){
	T c=a;
	a=b;
	b=c;
}
int rev[262144],N;
void pre(int n){
	int i,k;
	for(N=1,k=0;N<n;N<<=1)k++;
	for(i=0;i<N;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));
}
void fft(complex*a,int on){
	int i,j,k;
	complex t;
	for(i=0;i<N;i++){
		if(i<rev[i])swap(a[i],a[rev[i]]);
	}
	for(i=2;i<=N;i<<=1){
		for(j=0;j<N;j+=i){
			for(k=0;k<i>>1;k++){
				t=complex(cos(k*M_PI/(i/2)),on*sin(k*M_PI/(i/2)))*a[i/2+j+k];
				a[i/2+j+k]=a[j+k]-t;
				a[j+k]=a[j+k]+t;
			}
		}
	}
	if(on==-1){
		for(i=0;i<N;i++)a[i].x/=N;
	}
}
char s[100010],t[100010];
complex a[262144],b[262144],c[262144],d[262144];
int main(){
	int n,m,i,x,ans;
	double t3;
	scanf("%s%s",s,t);
	n=strlen(s);
	m=strlen(t);
	for(i=0;i>1;i++)swap(s[n-1-i],s[i]);
	for(i=0;i<n;i++){
		x=s[i]-'a'+1;
		a[i].x=x*x;
		c[i].x=x;
	}
	t3=0;
	for(i=0;i<m;i++){
		if(t[i]=='?')
			x=0;
		else
			x=t[i]-'a'+1;
		b[i].x=x;
		d[i].x=x*x;
		t3+=x*x*x;
	}
	pre(n<<1);
	fft(a,1);
	fft(b,1);
	for(i=0;i<N;i++)a[i]=a[i]*b[i];
	fft(a,-1);
	fft(c,1);
	fft(d,1);
	for(i=0;i<N;i++)b[i]=c[i]*d[i];
	fft(b,-1);
	ans=0;
	for(i=0;i<=n-m;i++){
		if(fabs((a[n-1-i]-b[n-1-i]*2+t3).x)<=eps)ans++;
	}
	printf("%d\n",ans);
	for(i=0;i<=n-m;i++){
		if(fabs((a[n-1-i]-b[n-1-i]*2+t3).x)<=eps)printf("%d\n",i);
	}
}

猜你喜欢

转载自www.cnblogs.com/jefflyy/p/8920498.html