Loading

P7469 [NOI Online 2021 提高组] 积木小赛

题目

给定两个字符串,在字符串 \(a\) 中找子序列,在 \(b\) 中找一个子串,询问有多少个子序列与子串相等,重复的字符串算一次。

思路

匹配和去重,想到哈希。

匹配,想到双指针。

每次枚举将要匹配的 \(b\) 数组的左端点,双指针匹配 \(a\) 数组,如果成功,那么将 \(b[i, j]\) 这一段的哈希值放入 vector,最后将 vector 排序 + 去重即可。

代码

#include <bits/stdc++.h>

using namespace std;
using ui64 = unsigned long long;

const int N = 3010;

ui64 base = 13331;

int n;
string a, b;
ui64 z[N], h[N];

ui64 query(int l, int r) {
    return h[r] - h[l - 1] * z[r - l + 1];
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    cin >> n;
    cin >> a >> b;
    a = ' ' + a;
    b = ' ' + b;

    h[0] = z[0] = 1;
    for (int i = 1; i <= n; i++) h[i] = h[i - 1] * base + b[i];
    for (int i = 1; i <= n; i++) z[i] = z[i - 1] * base;

    vector<ui64> res;
    for (int i = 1; i <= n; i++) {
        int r = -1;
        for (int j = i; j <= n; j++) {
            do {
                r++;
            } while (a[r] != b[j] && r <= n);
            if (r <= n) res.push_back(query(i, j));
        }
    }
    
    sort(res.begin(), res.end());
    res.erase(unique(res.begin(), res.end()), res.end());
    cout << res.size() << '\n';
    return 0;
}
posted @ 2024-09-12 09:24  SunnyYuan  阅读(2)  评论(0编辑  收藏  举报