题意:定义*号可匹配任意字符。给出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; }