1 条题解

  • 0
    @ 2026-10-26 20:16:52

    思路与算法

    按距离D排序。对区间维护生成多项式Π(1+V_i z)的0至6阶系数及最小V,线段树合并为截断卷积。查询得到区间多项式后,用b_0=1、b_j=a_j-minV·b_{j-1}逐项除掉最小项的因子,最后输出K!b_K模2^32。

    正确性说明

    多项式K阶系数把每个K元素子集的乘积恰计一次;样本顺序不同属于不同方案,所以乘K阶乘。最小V全局唯一,除去其因子精确排除仪器不选的区域。低阶系数只依赖低阶输入,截断卷积与递推除法不影响所求阶数。

    复杂度

    设最大阶B=6,排序O(nlogn),建树及初始化O(B²n),每查询O(B²logn+B),总O(nlogn+B²n+qB²logn),空间O(Bn)。

    易错点

    区间只有K个或更少区域时,删最小后不足K,直接0。模2^32为合数,不使用除法或逆元;uint32截断与uint64无符号乘加的低32位恰等价所需取模。距离和值互异均按原题保证。

    参考代码(C++11)

    #include <bits/stdc++.h>
    using namespace std;
    struct V {
        array<uint32_t, 7> p{};
        uint32_t mn = UINT32_MAX;
        V() {
            p[0] = 1;
        }
    };
    V mergeV(const V &a, const V &b) {
        V z;
        z.mn = min(a.mn, b.mn);
        for (int i = 1; i <= 6; i++) {
            uint64_t s = 0;
            for (int j = 0; j <= i; j++)
                s += uint64_t(a.p[j]) * b.p[i - j];
            z.p[i] = s;
        }
        return z;
    }
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int n, q;
        cin >> n >> q;
        vector<int> d(n);
        for (int &x : d)
            cin >> x;
        vector<pair<int, uint32_t>> a(n);
        for (int i = 0; i < n; i++) {
            uint32_t v;
            cin >> v;
            a[i] = {d[i], v};
        }
        sort(a.begin(), a.end());
        int S = 1;
        while (S < n)
            S *= 2;
        vector<V> tr(2 * S);
        for (int i = 0; i < n; i++) {
            d[i] = a[i].first;
            tr[S + i].p[1] = tr[S + i].mn = a[i].second;
        }
        for (int i = S - 1; i; i--)
            tr[i] = mergeV(tr[2 * i], tr[2 * i + 1]);
        while (q--) {
            int L, R, K;
            cin >> L >> R >> K;
            int l = lower_bound(d.begin(), d.end(), L) - d.begin(),
                r = upper_bound(d.begin(), d.end(), R) - d.begin();
            if (r - l <= K) {
                cout << 0 << '\n';
                continue;
            }
            V z;
            for (l += S, r += S; l < r; l /= 2, r /= 2) {
                if (l & 1)
                    z = mergeV(z, tr[l++]);
                if (r & 1)
                    z = mergeV(z, tr[--r]);
            }
            uint32_t b = 1;
            for (int i = 1; i <= K; i++)
                b = z.p[i] - uint32_t(uint64_t(z.mn) * b);
            for (int i = 2; i <= K; i++)
                b = uint64_t(b) * i;
            cout << b << '\n';
        }
    }
    
    • 1

    信息

    ID
    1851
    时间
    2000ms
    内存
    256MiB
    难度
    普及+
    标签
    递交数
    0
    已通过
    0
    上传者