洛谷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;
}

836605901b790cb382cf4c6dae1a024a

posted @ 2026-04-14 20:58  quanjun  阅读(2)  评论(0)    收藏  举报