洛谷P4173 残缺的字符串 题解 卷积解决带通配符字符串匹配问题
题目链接:https://www.luogu.com.cn/problem/P4173
解题思路:完全来自 Ebola大佬的博客
(理解了思路,自己手推了一下)
最后的式子用 FFT 求卷积。
示例程序:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e5 + 5;
using cd = complex<double>;
const double PI = acos(-1);
void fft(vector<cd>&a, int type) {
int n = a.size();
if (n == 1) return;
vector<cd> a0(n/2), a1(n/2);
for (int i = 0; i < n/2; i++) {
a0[i] = a[i * 2];
a1[i] = a[i * 2 + 1];
}
fft(a0, type);
fft(a1, type);
cd wn(cos(2 * PI / n), type * sin(2 * PI / n));
cd w(1, 0);
for (int k = 0; k < n/2; k++) {
cd t = w * a1[k];
a[k] = a0[k] + t;
a[k + n/2] = a0[k] - t;
w *= wn;
}
}
int m, n, a[maxn], b[maxn], limit = 1;
char s[maxn], t[maxn];
int query(int a[], int l, int r) {
int res = a[r];
if (l) res -= a[l-1];
return res;
}
vector<int> res;
double ans[maxn];
bool check(int x) {
long long res = 0;
for (int i = 0; i < m; i++)
res += a[i] * a[i] * a[i] * b[i+x]
+ a[i] * b[i+x] * b[i+x] * b[i+x]
- 2 * a[i] * a[i] * b[i+x] * b[i+x];
return res == 0;
}
int main() {
scanf("%d%d%s%s", &m, &n, s, t);
for (int i = 0; i < m; i++) {
if (s[i] == '*')
a[i] = 0;
else
a[i] = s[i] - '0' + 1;
}
for (int i = 0; i < n; i++) {
if (t[i] == '*')
b[i] = 0;
else
b[i] = t[i] - '0' + 1;
}
while (limit < n + m + 1)
limit <<= 1;
vector<cd> f(limit), g(limit);
for (int i = 0; i < m; i++)
f[i] = a[i] * a[i] * a[i];
for (int i = 0; i < n; i++)
g[n - i] = b[i];
fft(f, 1);
fft(g, 1);
for (int i = 0; i < limit; i++)
f[i] *= g[i];
fft(f, -1);
for (int i = 0; i+m-1 < n; i++)
ans[i] += f[n-i].real() / limit;
fill(f.begin(), f.end(), 0);
fill(g.begin(), g.end(), 0);
for (int i = 0; i < m; i++)
f[i] = a[i];
for (int i = 0; i < n; i++)
g[n - i] = b[i] * b[i] * b[i];
fft(f, 1);
fft(g, 1);
for (int i = 0; i < limit; i++)
f[i] *= g[i];
fft(f, -1);
for (int i = 0; i+m-1 < n; i++)
ans[i] += f[n-i].real() / limit;
fill(f.begin(), f.end(), 0);
fill(g.begin(), g.end(), 0);
for (int i = 0; i < m; i++)
f[i] = a[i] * a[i];
for (int i = 0; i < n; i++)
g[n - i] = b[i] * b[i];
fft(f, 1);
fft(g, 1);
for (int i = 0; i < limit; i++)
f[i] *= g[i];
fft(f, -1);
for (int i = 0; i+m-1 < n; i++)
ans[i] -= 2 * f[n-i].real() / limit;
for (int i = 0; i+m-1 < n; i++) {
if (abs(ans[i]) < 0.5) {
res.push_back(i+1);
}
}
int k = res.size();
printf("%d\n", k);
for (auto x : res)
printf("%d ", x);
return 0;
}

浙公网安备 33010602011771号