题目描述
很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串AAA和BBB,其中AAA串长度为mmm,BBB串长度为nnn。可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同程度的残缺。
你想对这两个串重新进行匹配,其中AAA为模板串,那么现在问题来了,请回答,对于BBB的每一个位置iii,从这个位置开始连续mmm个字符形成的子串是否可能与AAA串完全匹配?
输入输出格式
输入格式:第一行包含两个正整数mmm,nnn,分别表示AAA串和BBB串的长度。
第二行为一个长度为mmm的字符串AAA。
第三行为一个长度为nnn的字符串BBB。
两个串均仅由小写字母和*号组成,其中*号表示相应位置已经残缺。
输出格式:第一行包含一个整数kkk,表示BBB串中可以完全匹配AAA串的位置个数。
若k>0k > 0k>0,则第二行输出kkk个正整数,从小到大依次输出每个可以匹配的开头位置(下标从111开始)。
输入输出样例
说明
100100100%的数据满足1≤m≤n≤3000001 \leq m \leq n \leq 3000001≤m≤n≤300000。
定义卷积和为0则完全匹配
无通配符:
P(x)=∑[A(i)−B(x−m+i+1)]^2
*********************************************************************
有通配符:
我们设通配符的数值为0
P(x)=∑[A(i)−B(x−m+i+1)]^2 * A(i) * B(x−m+i+1)
把平方拆开,会出现三个卷积的形式
套路的把a翻转,
fft计算就行了
1 #include <algorithm> 2 #include <cmath> 3 #include <cstdio> 4 #include <queue> 5 6 typedef double D; 7 const D P = acos(-1); 8 const int N = 2e6 + 62; 9 10 struct $ { 11 D x, y; 12 inline $(D x_ = 0, D y_ = 0) : x(x_), y(y_) {} 13 inline $ operator+(const $& rhs) const { return $(x + rhs.x, y + rhs.y); } 14 inline $ operator-(const $& rhs) const { return $(x - rhs.x, y - rhs.y); } 15 inline $ operator*(const $& rhs) const { return $(x * rhs.x - y * rhs.y, x * rhs.y + y * rhs.x); } 16 inline $ operator/(D rhs) const { return $(x / rhs, y / rhs); } 17 }; 18 19 int lim, l, r[N]; 20 void fft($* a, int op) { 21 for (int i = 0; i < lim; i++) 22 if (i < r[i]) std::swap(a[i], a[r[i]]); 23 for (int i = 1; i < lim; i <<= 1) { 24 $ wn(cos(P / i), op * sin(P / i)); 25 for (int j = 0; j < lim; j += i << 1) { 26 $ w(1); 27 for (int k = 0; k < i; k++, w = w * wn) { 28 $ x = a[j + k], y = w * a[i + j + k]; 29 a[j + k] = x + y; 30 a[i + j + k] = x - y; 31 } 32 } 33 } 34 if (op == -1) 35 for (int i = 0; i < lim; i++) a[i] = a[i] / lim; 36 } 37 38 $ a2[N], b2[N], c[N]; 39 int m, n, a[N], b[N]; 40 std::queue<int> q; 41 char s1[N], s2[N]; 42 int main() { 43 scanf("%d%d%s%s", &m, &n, s1, s2); 44 for (lim = 1; lim < n * 2; lim <<= 1) l++; 45 for (int i = 1; i < lim; i++) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1)); 46 for (int i = 0; i < m; i++) 47 if (s1[m - i - 1] != '*') a[i] = s1[m - i - 1] - 'a' + 1; 48 for (int i = 0; i < n; i++) 49 if (s2[i] != '*') b[i] = s2[i] - 'a' + 1; 50 51 for (int i = 0; i < m; i++) a2[i] = $(a[i] * a[i] * a[i]); 52 for (int i = 0; i < n; i++) b2[i] = $(b[i]); 53 fft(a2, 1), fft(b2, 1); 54 for (int i = 0; i < lim; i++) c[i] = a2[i] * b2[i]; 55 56 for (int i = 0; i < lim; i++) a2[i] = b2[i] = $(); 57 for (int i = 0; i < m; i++) a2[i] = $(a[i] * a[i]); 58 for (int i = 0; i < n; i++) b2[i] = $(b[i] * b[i]); 59 fft(a2, 1), fft(b2, 1); 60 for (int i = 0; i < lim; i++) c[i] = c[i] - a2[i] * b2[i] * 2; 61 62 for (int i = 0; i < lim; i++) a2[i] = b2[i] = $(); 63 for (int i = 0; i < m; i++) a2[i] = $(a[i]); 64 for (int i = 0; i < n; i++) b2[i] = $(b[i] * b[i] * b[i]); 65 fft(a2, 1), fft(b2, 1); 66 for (int i = 0; i < lim; i++) c[i] = c[i] + a2[i] * b2[i]; 67 68 fft(c, -1); 69 for (int i = m - 1; i < n; i++) 70 if (fabs(c[i].x) < 0.5) q.push(i - m + 2); 71 for (printf("%lu\n", q.size()); !q.empty(); q.pop()) printf("%d ", q.front()); 72 }