[BZOJ4259] 残缺的字符串 (FFT)

题意:定义*号可匹配任意字符。给出A串,B串,求A串在B中完全匹配的所有位置。

将*号视作0,则两个等长的串可匹配当且仅当Σ(a[i]-b[i])^2*a[i]*b[i]==0。将A串和B串最左边对齐,每次上式都要重算一次,不科学。所以讲A串先反转过来然后补上*号,就是卷积啦。

原来的万径人踪灭一题当中用FFT来求了回文串,这里又能玩字符串匹配,真是太6了。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define clr(a) memset(a,0,sizeof a)
#define DB double
const int MAXN = 300005;
const int MAXL = MAXN*4;
int N, M;

const DB PI = acos(-1);
struct cpx
{
	DB r, i;
	cpx() {}
	cpx(DB a, DB b):r(a), i(b){};
	inline cpx operator + (cpx b) { return cpx(r+b.r, i+b.i); }
	inline cpx operator - (cpx b) { return cpx(r-b.r, i-b.i); }
	inline cpx operator * (cpx b) { return cpx(r*b.r - i*b.i, r*b.i+i*b.r); }
};
namespace FFT
{
	int r[MAXL], L;
	cpx a[MAXL], b[MAXL];
	void fft(cpx*a, int flag, int N)
	{
		rep(i, 0, N-1) if (i<r[i]) swap(a[i], a[r[i]]);
		for (int i = 1; i<N; i<<=1)
		{
			cpx wn(cos(PI/i), flag*sin(PI/i));
			for (int j = 0; j<N; j+=i<<1)
			{
				cpx w(1, 0);
				for (int k = 0; k<i; ++k, w=w*wn)
				{
					cpx x = a[j+k], y = w*a[j+k+i];
					a[j+k] = x+y, a[j+k+i] = x-y;
				}
			}
		}
		if (flag<0) rep(i, 0, N-1) a[i].r /= N;
	}
	void mul(DB*pol1, DB*pol2, int N, int M)
	{
		rep(i, 0, N) a[i] = cpx(pol1[i], 0);
		rep(i, 0, M) b[i] = cpx(pol2[i], 0);
		int tn = N+1, tm = M+1; r[0] = 0;
		for (M+=N, L=0, N=1; N<=M; N<<=1) ++L;
		rep(i, tn, N) a[i] = cpx(0, 0);
		rep(i, tm, N) b[i] = cpx(0, 0);
		rep(i, 0, N) r[i] = (r[i>>1]>>1)|((i&1)<<(L-1));
		fft(a, 1, N); fft(b, 1, N);
		rep(i, 0, N) a[i] = a[i]*b[i];
		fft(a, -1, N);
		rep(i, 0, M) pol1[i] = a[i].r;
	}
}

char A[MAXN], B[MAXN];

DB p1[MAXN*2], p2[MAXN*2], f[MAXN];
int an, ans[MAXN];

int main()
{
	scanf("%d%d", &N, &M);
	scanf("%s%s", A, B);
	reverse(A, A+N);
	rep(i, 0, N-1)
	{
		if (A[i] == '*') A[i] = 0;
		else A[i] -= 'a'-1;
	}
	rep(i, 0, M-1)
	{
		if (B[i] == '*') B[i] = 0;
		else B[i] -= 'a'-1;
	}

	rep(i, 0, N-1) p1[i] = 1.0*A[i]*A[i]*A[i];
	rep(i, 0, M-1) p2[i] = B[i];
	FFT::mul(p1, p2, N-1, M-1);
	rep(i, 0, M-1) f[i] += p1[i];

	rep(i, 0, N-1) p1[i] = 1.0*A[i]*A[i];
	rep(i, 0, M-1) p2[i] = 1.0*B[i]*B[i];
	FFT::mul(p1, p2, N-1, M-1);
	rep(i, 0, M-1) f[i] -= 2*p1[i];

	rep(i, 0, N-1) p1[i] = A[i];
	rep(i, 0, M-1) p2[i] = 1.0*B[i]*B[i]*B[i];
	FFT::mul(p1, p2, N-1, M-1);
	rep(i, 0, M-1) f[i] += p1[i];
	
	rep(i, N-1, M-1) if (int(f[i]+0.2)==0) ans[++an] = i+1-(N-1);
	printf("%d\n", an);
	rep(i, 1, an) printf("%d%c", ans[i], i!=an?' ':'\n');
	return 0;
}


你可能感兴趣的:([BZOJ4259] 残缺的字符串 (FFT))