• 题解:「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;
    }
    
  • 相关阅读:
    Error:Execution failed for task ':app:transformClassesWithDexForDebug'.
    Appcan——Box
    基于SSH框架的网上商城的质量属性
    框架的选择
    软件体系结构的认识
    Cocos2d-x项目创建方式
    一、设计模式简介
    数组与字符串四(例子、使用(2))
    数组与字符串三(Cocos2d-x 3.x _Array容器)
    数组与字符串二(例子、使用)
  • 原文地址:https://www.cnblogs.com/Ax-Dea/p/14404160.html
Copyright © 2020-2023  润新知