题解:「USACO 2020.2 Platinum」Help Yourself

首先考虑 (k = 1) 的情况。

发现每条线段对前后的答案都有影响,所以按左端点排序,从左到右处理。

(f_i) 表示以 (i) 为结尾的线段集合的答案,最终答案即为 (sum_{i=1}^{2n} f_i)

对于每条加进来的线段 (egin{bmatrix}l,rend{bmatrix}) 对于不同 (f_i) 的贡献进行分类讨论。

  1. 对于所有 (i < l) ,此时加入这条线段后,对 (f_r) 的贡献即为 (f_i + 1) ,可以表达为 (f_r gets f_r + sum_{i=1}^{l-1} f_i+1)
  2. 对于所有 (iin[l,r]) ,加入线段后,复杂度不变,所以对 (f_r) 的贡献即为 (f_i) ,可以表达为 (f_r gets f_r + sum_{i=l}^{r} f_i)
  3. 对于所有 (i > r) ,因为按照左端点排序,所以加入线段后,复杂度不变,所以 (f_i)(f_i) 的贡献即为 (f_i) ,可以表达为 (f_i gets f_i imes 2)

可以直接前缀和或者线段树维护。

考虑 (k > 1)

发现棘手的地方在于维护第一种情况出现的 (sum_{i=1}^{l-1} (f_i+1)^k)

这里有两种解决方案。

方案一:

根据二项式定理 ((f_i+1)^k = sum_{j=0}^{k} {k choose j} f_i^j)

因为 (kleq 10) ,直接用线段树维护每个指数所对应的值即可。

方案二:

大力拆式子。

(g_s) 表示 (k=1) 时线段集合 (s) 的答案,发现最终答案可以表达为 (sum_s g_s^k)

直接套路次幂拆第二类斯特林数,得到:

[sum_s sum_{i=0}^{k} egin{Bmatrix}k\iend{Bmatrix} i! {g_s choose i} ]

换一下求和顺序,得:

[sum_{i=0}^k egin{Bmatrix}k\iend{Bmatrix} i! sum_s {g_s choose i} ]

(S_i) 表示以第 (i) 个节点结束的线段集合的集合,维护对象改为对于每一个 (j) ,求:

[f_{i,j} = displaystyle{sum_{sin S_i} {g_s choose j}} ]

再看一下上面的讨论,发现后两种针对总体贡献,直接翻倍相加即可。

问题变为如何处理 (displaystyle{{g_schoose j} ightarrow {g_s+1 choose j}})

根据加法恒等式发现有转移:

[{g_s + 1 choose j} gets {g_s choose j} + {g_s choose j-1} ]

可以用线段树维护每个 (f_{i,j}) ,发现转移后面的东西已经都维护好了,直接转移即可,具体表达 (f_{i,j} gets f_{i,j} + f_{i,j-1})
时间复杂度 (mathcal{O}(nklog n + nk))

Code(C++):

#include <bits/stdc++.h>
#define forn(i,s,t) for(register int i=(s);i<=(t);++i)
using namespace std;
typedef long long LL;
const int N = 1e5 + 3, M = 4e5 + 1e2, Mod = 1e9 + 7;
template<typename T>inline void redn(T &ret) {
    static char ch;
    ret = 0, ch = getchar();

    while (!isdigit(ch))
        ch = getchar();

    while (isdigit(ch))
        ret = (ret << 1) + (ret << 3) + ch - 48, ch = getchar();
}
int k;
LL wgt[11], trans[11];
class SegTree {
private:
    int L[M], R[M], sl;
    LL val[M][11], tag[M];
    inline void push_up(int p) {
        forn(i, 0, k) val[p][i] = val[L[p]][i] + val[R[p]][i], val[p][i] %= Mod;
    }
    inline void Opt(int p, LL value) {
        forn(i, 0, k) val[p][i] = val[p][i] * value % Mod;
        tag[p] = tag[p] * value % Mod;
    }
    inline void push_down(int p) {
        Opt(L[p], tag[p]), Opt(R[p], tag[p]);
        tag[p] = 1ll;
    }
public:
    int rt;
    void Bld(int &p, int l, int r) {
        p = ++sl, tag[p] = 1;

        if (l == r)
            return ;

        int mid = l + r >> 1;
        Bld(L[p], l, mid), Bld(R[p], mid + 1, r);
        push_up(p);
    }
    void Qry(int p, int l, int r, int nl, int nr) {
        if (l == nl && nr == r) {
            forn(i, 0, k) wgt[i] = wgt[i] + val[p][i], wgt[i] %= Mod;
            return ;
        }

        (tag[p] ^ 1) &&(push_down(p), 0);
        int mid = nl + nr >> 1;

        if (r <= mid)
            Qry(L[p], l, r, nl, mid);
        else if (l > mid)
            Qry(R[p], l, r, mid + 1, nr);
        else
            Qry(L[p], l, mid, nl, mid), Qry(R[p], mid + 1, r, mid + 1, nr);
    }
    void Upd(int p, int l, int r, int pos) {
        if (l == r) {
            forn(i, 0, k) val[p][i] = val[p][i] + trans[i], val[p][i] %= Mod;
            return ;
        }

        (tag[p] ^ 1) &&(push_down(p), 0);
        int mid = l + r >> 1;

        if (pos <= mid)
            Upd(L[p], l, mid, pos);
        else
            Upd(R[p], mid + 1, r, pos);

        push_up(p);
    }
    void Mul(int p, int l, int r, int nl, int nr) {
        if (l == nl && nr == r)
            return Opt(p, 2ll);

        (tag[p] ^ 1) &&(push_down(p), 0);
        int mid = nl + nr >> 1;

        if (r <= mid)
            Mul(L[p], l, r, nl, mid);
        else if (l > mid)
            Mul(R[p], l, r, mid + 1, nr);
        else
            Mul(L[p], l, mid, nl, mid), Mul(R[p], mid + 1, r, mid + 1, nr);

        push_up(p);
    }
} T;
int n, m, l[N], r[N], id[N];
LL S[11][11], fac[11], Ans;
inline bool cmp(int A, int B) {
    return l[A] < l[B];
}
int main() {
    redn(n), redn(k);
    m = (n << 1) + 1;
    T.Bld(T.rt, 0, m);
    forn(i, 1, n) redn(l[i]), redn(r[i]), id[i] = i;
    sort(id + 1, id + n + 1, cmp);
    trans[0] = 1;
    T.Upd(T.rt, 0, m, 0);
    forn(i, 1, n) {
        forn(j, 0, k) wgt[j] = 0;
        T.Qry(T.rt, 0, l[id[i]] - 1, 0, m);
        trans[0] = wgt[0];
        forn(j, 1, k) trans[j] = wgt[j] + wgt[j - 1], trans[j] %= Mod;
        forn(j, 0, k) wgt[j] = 0;
        T.Qry(T.rt, l[id[i]], r[id[i]], 0, m);
        forn(j, 0, k) trans[j] = trans[j] + wgt[j], trans[j] %= Mod;
        T.Upd(T.rt, 0, m, r[id[i]]);
        T.Mul(T.rt, r[id[i]] + 1, m, 0, m);
        forn(j, 0, k) wgt[j] = 0ll;
        T.Qry(T.rt, 0, m, 0, m);
    }
    forn(i, 0, k) wgt[i] = 0;
    T.Qry(T.rt, 0, m, 0, m);
    S[0][0] = 1;
    forn(i, 1, k) forn(j, 1, k) S[i][j] = (S[i - 1][j - 1] + 1ll * j * S[i - 1][j] % Mod) % Mod;
    fac[0] = 1ll;
    forn(i, 1, k) fac[i] = 1ll * i * fac[i - 1] % Mod;
    forn(i, 0, k) Ans += S[k][i] * fac[i] % Mod * wgt[i] % Mod, Ans %= Mod;
    printf("%lld
", Ans);
    return 0;
}
原文地址:https://www.cnblogs.com/Ax-Dea/p/14404160.html