首页 > 其他分享 >CF1827F 题解

CF1827F 题解

时间:2023-12-31 21:45:52浏览次数:23  
标签:maxx minn 题解 back lmin lmax type CF1827F

不妨先考虑一个弱化版的问题,这个问题和原来的问题仅有一个区别:\(k\) 是给定整数。
称最后 \(n-k\) 个数是“特殊的”。那么我们可以注意到,每个特殊的数字的极大段必然递增放置或者递减放置。例如我们有排列 \([7,5,8,1,4,2,6,3]\) 而且 \(k=2\),那么极大段的下标应该是 \([1,4],[6,6],[8,8]\)。
我们把所有的好子串分成三部分,一部分是前缀,一部分是后缀,剩下的是第三部分。对于前两种子串,用 CF526F 的算法就可以顺利解决,这里略去讲解。
我们定义一个优雅的数组 \(ele\) 满足 \(\forall i,ele_i<ele_{i+1}\) 且 \(p[ele_i,k]\) 包括了连续非特殊数字。
接下来,我们尝试着向已有的排列(即排列的一部分)中添加特殊数字。
对于这个优雅数组,我们从右向左的处理,而特殊的数字则从左向右加。那么对于一个数组中的元素 \(ele_i\),先把特殊数字放进去以让答案加一,然后考虑两个极大段,他们分别包含 \(mn_i-1\) 和 \(mx_i+1\),其中 \(mn,mx\) 分别为 \(p[ele_i,k]\)。我们可以把这俩段放上以增大答案。
另一方面,注意到 \(mx_i=mx_{i+1}=\dots=mx_{j}\) 的时候,如果 \(\forall i\le x<j, p[ele_x,ele_{x+1}]\) 是好的,那么他们都可以获得贡献。
对每个有相同 \(mn\) 的优雅位置分别计算即可。

那么对于每一个 \(k\),我们预处理 \(mn,mx\) 等价位置的前缀。转移时我们只需要考虑两个优雅位置:一个是 \(k\)(此时,若 \(p_{k-1}<p_k\),直接令 \(j=lst(p_j>p_k)\),反之亦然),下一个当然就是 \(j\) 的下一个位置,而显然它具有性质:它必然是最后一个 \(mn,mx\) 等价位置。那么处理这些位置不会影响后面的位置。复杂度显然是 \(O(n\log n)\) 的。

核心代码大致如下:

void work(int i, int j, bool recalc) {
    int imin = calc_min(i), imax = calc_max(i), jmin = calc_min(j), jmax = calc_max(j);
    int type;
    if (recalc) {
        mid -= 1ll * lmax[j].maxx * (rr[jmax] - jmax - 1);
        mid -= 1ll * lmin[j].maxx * (jmin - ll[jmin] - 1);
    }

    if (imax == jmax) {
        if (!recalc)
            mid -= 1ll * lmax[i].maxx * (rr[imax] - imax - 1);

        if (jmin - imin == j - i)
            type = 0;
        else {
            type = 2 - (imin + j - i == ll[jmin] + 1);
        }
        if (type == 2)
            lmax[j] = cop(1, lmax[i].maxx, type);
        else if (lmax[i].type == 0)
            lmax[j] = cop(lmax[i].curr + 1, lmax[i].maxx, type);
        else
            lmax[j] = cop(2, lmax[i].maxx, type);

    } else
        lmax[j] = {1, 1, 3};
    if (imin == jmin) {
        if (!recalc)
            mid -= 1ll * lmin[i].maxx * (imin - ll[imin] - 1);

        if (imax - jmax == j - i)
            type = 0;
        else if (imax + i - j == rr[jmax] - 1)
            type = 1;
        else
            type = 2;

        if (type == 2)
            lmin[j] = cop(1, lmin[i].maxx, type);
        else if (lmin[i].type == 0)
            lmin[j] = cop(lmin[i].curr + 1, lmin[i].maxx, type);
        else
            lmin[j] = cop(2, lmin[i].maxx, type);

    } else
        lmin[j] = {1, 1, 3};

    mid += 1ll * lmax[j].maxx * (rr[jmax] - jmax - 1);
    mid += 1ll * lmin[j].maxx * (jmin - ll[jmin] - 1);
}

void solve() {
    elem.clear();
    minn.assign(1, 0), maxx.assign(1, 0);
    set<int> ss;
    ss.insert(0), ss.insert(n + 1);
    pre = 0, suf = 1ll * n * (n + 1) / 2, mid = 0;
    cout << suf << ' ';
    ll[n] = 0, rr[0] = n;
    seg1.build(1, 1, n);
    init();
    for (int i = 1; i <= n; i++) {
        while (elem.size()) {
            int j = elem.back();
            int jmin = calc_min(j), jmax = calc_max(j);
            if (get_min_pos(min(jmin, a[i]), max(jmax, a[i])) < j) {
                mid -= 1ll * lmax[j].maxx * (rr[jmax] - jmax - 1);
                mid -= 1ll * lmin[j].maxx * (jmin - ll[jmin] - 1);
                elem.pop_back();
                if (elem.size()) {
                    if (lmax[j].type < 3)
                        mid += 1ll * lmax[elem.back()].maxx * (rr[jmax] - jmax - 1);
                    if (lmin[j].type < 3)
                        mid += 1ll * lmin[elem.back()].maxx * (jmin - ll[jmin] - 1);
                }
            } else
                break;
        }
        if (elem.size()) {
            int j = elem.back();
            int jmin = calc_min(j), jmax = calc_max(j);
            mid -= 1ll * lmax[j].maxx * (rr[jmax] - jmax - 1);
            mid -= 1ll * lmin[j].maxx * (jmin - ll[jmin] - 1);
        }
        auto it = ss.upper_bound(a[i]);
        suf -= 1ll * (*it - a[i]) * (a[i] - *prev(it));
        connect(*prev(it), a[i]), connect(a[i], *it);
        ss.insert(a[i]);
        while (maxx.size() > 1 && a[maxx.back()] < a[i]) {
            seg1.easy_update(maxx[maxx.size() - 2] + 1,
                             maxx.back(), a[i] - a[maxx.back()]);
            maxx.pop_back();
        }
        while (minn.size() > 1 && a[minn.back()] > a[i]) {
            seg1.easy_update(minn[minn.size() - 2] + 1,
                             minn.back(), a[minn.back()] - a[i]);
            minn.pop_back();
        }
        maxx.push_back(i), minn.push_back(i);
        if (elem.size()) {
            int j = elem.back();
            int jmin = calc_min(j), jmax = calc_max(j);
            mid += 1ll * lmax[j].maxx * (rr[jmax] - jmax - 1) + 1ll * lmin[j].maxx * (jmin - ll[jmin] - 1);
            work(j, i, 0);
        } else {
            lmax[i] = lmin[i] = {1, 1, 3};
            mid += rr[a[i]] - ll[a[i]] - 2;
        }
        elem.push_back(i);
        if (minn.size() >= 2) {
            int k = search(minn[minn.size() - 2]);
            if (k > 0 && k < elem.size())
                work(elem[k - 1], elem[k], 1);
        }
        if (maxx.size() >= 2) {
            int k = search(maxx[maxx.size() - 2]);
            if (k > 0 && k < elem.size())
                work(elem[k - 1], elem[k], 1);
        }
        cout << pre + elem.size() + mid + suf << ' ';

        pre += seg1.nodes[1].cnt;
    }
    cout << '\n';
}

标签:maxx,minn,题解,back,lmin,lmax,type,CF1827F
From: https://www.cnblogs.com/Piggy424008/p/17938041/cf1827f-ti-jie

相关文章

  • P4875 题解
    显然这道题的解法与\(8\)强相关。从这一点下手,我们不难想到先对每一种奶牛做前缀和,这样我们可以做到\(O(8)\)查询每个区间是否可行,从而有了一个\(O(4n^2)\)的纯暴力做法。不知道多少pts,反正不是正解。下一步我们考虑优化。如果我们能快速地找到哪些区间是合法的,那么时间复......
  • P5138 题解
    因为本题的代码难度远大于解法的思考,因此这里提供一种好写的写法。做法不再赘述,就是转化为\(depth\)差以后上线段树分别维护两个信息以后求和。题解中大多数使用同一个线段树维护两个信息,可读性并不高,且比较难写。事实上我们注意到两棵线段树仅有初始的信息不一样,剩下需要支持......
  • P4434 题解
    远古模拟赛里的一道题,前来写篇题解记录一下。我们考虑一个显然的转化。将每条边染色,那么原问题等价于求下面的染色的方案数:对于每个点对\(a,b\),我们记\(\operatorname{lca}(a,b)=c\)有\(a\simc\)上的所有边同色。\(b\simc\)上的所有边同色。\(a\simc\)和\(b\simc......
  • CF958E1 题解
    Meaning在二维平面内,有位置不同且不存在三点共线的\(R\)个红点和\(B\)个黑点,判断是否能用一些互不相交的线段连接每一个点,使得每条线段的两端都分别是黑点和白点。Solution当\(R\ne{B}\)时,显然无法实现红点与黑点的两两组合,故题干所述的情况一定不存在。当\(R=B\)时,我......
  • P5765 [CQOI2005] 珠宝 题解
    P5765[CQOI2005]珠宝题解思路好题,注意到有性质:颜色数最多为\(\lfloor\log_2n\rfloor+1\),有了这个性质之后直接树形DP糊上去就过了。简要的证明:考虑一个点,显然一种颜色即可。对于一个颜色为\(c\)的点,其儿子至少有\(c-1\)个,且为\(1\simc-1\)的排列,这样可......
  • P2898 [USACO08JAN] Haybale Guessing G 题解
    题目传送门前置知识二分答案|并查集解法对条件的合法性判断其他题解已经讲得很明白了,这里不再赘述。这里主要讲一下用并查集实现黑白染色问题。以下内容称被覆盖为黑色,不被覆盖为白色。本题因为是单向染色,即从白到黑,故可类似luoguP1840ColortheAxis和D的并查集或......
  • 二叉树面试题解析
    二叉树面试题解析判断相同的树/***Definitionforabinarytreenode.*publicclassTreeNode{*intval;*TreeNodeleft;*TreeNoderight;*TreeNode(){}*TreeNode(intval){this.val=val;}*TreeNode(intval,TreeNode......
  • 剑指Offer Java题解(前3道题)
    目录1.二维数组中的查找2. 替换空格3. 从尾到头打印链表1.二维数组中的查找题目链接:传送。方法一,暴力枚举。参考代码:packageproblem01;/***@Authorsyrdbt*@Date2019/7/314:05*二维数组中的查找*方法一,暴力枚举*/publicclassSolution{publicboole......
  • 杭州电子科技大学2023新生赛 E 树 题解
    Question杭州电子科技大学2023新生赛E树给定一颗包含\(n\)个节点的带边权的树,定义\(xordist(u,v)\)为节点\(u\)到\(v\)的简单路径上所有边权值的异或和有\(q\)次询问,每次给出lrx求\(\sum_{i=l}^rxordist(i,x)\)的值Solution考试的时候脑子坏了对于一条......
  • 【省选联考2020】树 题解
    省选题解第一发~【省选联考2020】树我和这道题还挺有缘分的。有一次看大佬的省选游记(不知道是哪一年),然后提到有一道是01trie整体加一,当时我就印象深刻,然后在oiwiki上看了一下,心想这整体加一也只能从低位到高位维护01trie啊,又不能查询最大值,有什么卵用(划掉)。这是两周前的事......