题解:「USACO 2020.2 Platinum」Help Yourself

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

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

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

对于每条加进来的线段 \(\begin{bmatrix}l,r\end{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. 对于所有 \(i\in[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 \times 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\)

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

方案二:

大力拆式子。

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

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

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

换一下求和顺序,得:

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

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

\[f_{i,j} = \displaystyle{\sum_{s\in S_i} {g_s \choose j}} \]

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

问题变为如何处理 \(\displaystyle{{g_s\choose j} \rightarrow {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}(nk\log 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\n", Ans);
    return 0;
}
posted @ 2021-02-15 18:04  AxDea  阅读(74)  评论(0编辑  收藏  举报