P9149 串串题 Sol

调了半天,原因是在没有输入 w 的情况下 resize w 大小的 vector


很直观的做法是把 a1n 中没有在 b1m 中出现过的数删掉,生成 c1len

记录一个 g1len 表示每一个 c 中的元素原来在 a 中的位置。

那么 c 中对于每一个长度为 m 的区间 [l,r],可以发现,如果要它与 b 匹配,那么需要在 a 数组中删掉满足 i[gl,gr] 且没有在 b 中出现过的数 ai。令这些 ai 去重后个数为 t

钦定这 t 个数之后,发现这个区间外面的数随便删。

v 表示在 b 中没出现过的数的个数。

那么方案数显然就是在没出现的剩余 vt 个数中选择 dt 个数。

也就是 (vtdt),如此平移区间就可以计算啦。

#include <bits/stdc++.h>
#define int long long
using ull = unsigned long long;
using namespace std;

const int N = 1e6 + 10, P = 1e9 + 7;
const ull bas = 998244853; ull pw[N], has[N];
int t, n, m, w, d, a[N], b[N];
int inv[N], fac[N], ifac[N];

inline void init() {
    inv[0] = inv[1] = fac[0] = fac[1] = ifac[0] = ifac[1] = 1;
    pw[0] = 1, pw[1] = bas;
    for (int i = 2; i <= 1e6; ++i) {
        inv[i] = inv[P % i] * (P - P / i) % P;
        fac[i] = fac[i - 1] * i % P, ifac[i] = ifac[i - 1] * inv[i] % P;
        pw[i] = pw[i - 1] * bas;
    }
    return ;
}

inline int C(int x, int y) {
    if (x < 0 || y < 0 || x < y) return 0;
    return fac[x] * ifac[y] % P * ifac[x - y] % P;
} inline ull query(int l, int r) {
    return has[r] - pw[r - l + 1] * has[l - 1];
}

inline void solve() {
    vector <int> g, cnt; vector <bool> vis;
    cin >> n >> m >> w >> d; ull H = 0;
    g.push_back(0), cnt.resize(w + 10), vis.resize(w + 10);
    for (int i = 1; i <= n; ++i) cin >> a[i];
    for (int i = 1; i <= m; ++i) {
        cin >> b[i], vis[b[i]] = true;
        H = H * bas + b[i];
    }
    for (int i = 1; i <= n; ++i) if (vis[a[i]]) g.push_back(i);
    int siz = 0, all = 0, res = 0, len = g.size() - 1;
    if (len < m) return cout << 0 << endl, void();
    for (int i = 1; i <= w; ++i) if (!vis[i]) ++all;
    for (int i = 1; i <= m; ++i) has[i] = has[i - 1] * bas + a[g[i]];
    for (int i = g[1]; i <= g[m]; ++i)
        if (!vis[a[i]]) if (++cnt[a[i]] == 1) ++siz;
    (res += (query(1, m) == H) * C(all - siz, d - siz)) %= P;
    for (int i = 2; i + m - 1 <= len; ++i) {
        for (int j = g[i - 1]; j < g[i]; ++j)
            if (!vis[a[j]]) if (!(--cnt[a[j]])) --siz;
        for (int j = g[i + m - 2] + 1; j <= g[i + m - 1]; ++j)
            if (!vis[a[j]]) if (++cnt[a[j]] == 1) ++siz;
        has[i + m - 1] = has[i + m - 2] * bas + a[g[i + m - 1]];
        (res += (query(i, i + m - 1) == H) * C(all - siz, d - siz)) %= P;
    }
    return cout << res << endl, void();
}

signed main() {
    ios_base::sync_with_stdio(false); cin.tie(0), cout.tie(0);
    init(); cin >> t; while (t--) solve(); return 0;
}
posted @   MistZero  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示