P4173 残缺的字符串 (带通配符的FFT字符匹配)

题目描述

很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串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开始)。

输入输出样例

输入样例#1: 复制
3 7
a*b
aebr*ob
输出样例#1: 复制
2
1 5

说明

100100100%的数据满足1≤m≤n≤3000001 leq m leq n leq 3000001mn300000。







定义卷积和为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
", q.size()); !q.empty(); q.pop()) printf("%d ", q.front());
72 }
原文地址:https://www.cnblogs.com/zhangbuang/p/11068838.html