首页 > 其他分享 >【题解】P4755 Beautiful Pair

【题解】P4755 Beautiful Pair

时间:2023-01-22 17:12:10浏览次数:62  
标签:Beautiful idx int 题解 top stk maxn 区间 P4755

麻了,这么多典题没做过……

思路

分治 / 笛卡尔树。

这一类和区间最值相关的区间端点对计数应该都可以用这种做法做。

由于求的是最大值,不妨从大到小考虑每个 \(a_i\) 的贡献。

显然存在一个连续的区间 \([l_i, r_i]\),使得这个区间任意包含 \(i\) 的子区间最大值均为 \(a_i\).

所以与 \(a_i\) 相关的贡献只有可能在这个区间中产生。

这道题中 \(l_i = \max\limits_{j < i, a_j \geq a_i} j + 1, r_i = \min\limits_{j > i, a_j > a_i} j - 1\),注意要特判一下边界情况。

一个思路是枚举 \([l_i, i], [i, r_i]\) 中较短的一个区间,尝试将当中的每一个位置作为区间一侧的端点,然后在另一侧计数满足条件的端点个数。这个过程可以用数据结构维护。

这种做法本质上是分治,等价于从大到小考虑 \(a_i\) 的贡献,不断将当前的分治区间划分成两部分。

考虑这个分治的逆过程,相当于不断将两个小的合并区间合并。

因为每次遍历较小的区间,所以本质上是启发式合并,故而复杂度不超过 \(O(n \log n)\).

这道题中可以转化成询问某个区间内小于等于某个数的值个数。考虑将询问差分一下,离线下来挂在相应的位置询问就行。

还有另外一种构造笛卡尔树的做法,本质上是相同的,只不过是考虑在笛卡尔树上进行中序遍历来访问区间而已。可能这种做法比离线好调一点。

这个做法实际上是利用笛卡尔树的性质(大根堆)来求 \([l_i, r_i]\),可能泛用性没有分治做法高。

两种做法的时间复杂度都是 \(O(n \log^2 n)\)

另一道可以用这个方法解决的题目是 CF1777F

代码

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;

typedef long long ll;

#define pb push_back

const int maxn = 1e5 + 5;

int n;
int top, stk[maxn], idx[maxn];
int a[maxn], b[maxn];
int lft[maxn], rgt[maxn];
vector<int> val[maxn], coe[maxn];

namespace BIT
{
    int c[maxn];

    int lowbit(int x) { return x & (-x); }

    void update(int p, int w) { for (int i = p; i <= n; i += lowbit(i)) c[i] += w; }

    int query(int p) { int res = 0; for (int i = p; i; res += c[i], i -= lowbit(i)) ; return res; }
}

int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]), b[i] = a[i];
    for (int i = 1; i <= n; i++)
    {
        while (top && a[i] > stk[top]) top--;
        lft[i] = top ? idx[top] + 1 : 1, stk[++top] = a[i], idx[top] = i;
    }
    top = 0;
    for (int i = n; i >= 1; i--)
    {
        while (top && a[i] >= stk[top]) top--;
        rgt[i] = top ? idx[top] - 1 : n, stk[++top] = a[i], idx[top] = i;
    }
    // for (int i = 1; i <= n; i++) printf("%d %d\n", lft[i], rgt[i]);
    for (int i = 1; i <= n; i++)
    {
        if (i - lft[i] <= rgt[i] - i)
        {
            val[i - 1].pb(1), coe[i - 1].pb(-1);
            val[rgt[i]].pb(1), coe[rgt[i]].pb(1);
            for (int j = lft[i]; j <= i - 1; j++)
            {
                val[i - 1].pb(a[i] / a[j]), coe[i - 1].pb(-1);
                val[rgt[i]].pb(a[i] / a[j]), coe[rgt[i]].pb(1);
            }
        }
        else
        {
            val[lft[i] - 1].pb(1), coe[lft[i] - 1].pb(-1);
            val[i].pb(1), coe[i].pb(1);
            for (int j = i + 1; j <= rgt[i]; j++)
            {
                val[lft[i] - 1].pb(a[i] / a[j]), coe[lft[i] - 1].pb(-1);
                val[i].pb(a[i] / a[j]), coe[i].pb(1);
            }
        }
    }
    sort(b + 1, b + n + 1);
    int m = unique(b + 1, b + n + 1) - b - 1;
    for (int i = 1; i <= n; i++) a[i] = lower_bound(b + 1, b + m + 1, a[i]) - b;
    ll ans = 0;
    for (int i = 1; i <= n; i++)
    {
        BIT::update(a[i], 1);
        for (int j = 0, v, c; j < val[i].size(); j++)
        {
            v = (val[i][j] >= b[m] ? m : upper_bound(b + 1, b + m + 1, val[i][j]) - b - 1), c = coe[i][j];
            ans += BIT::query(v) * c;
        }
    }
    printf("%lld\n", ans);
    return 0;
}

标签:Beautiful,idx,int,题解,top,stk,maxn,区间,P4755
From: https://www.cnblogs.com/lingspace/p/p4755.html

相关文章

  • 【题解】Codeforces Round #845 (Div. 2) and ByteRace 2023
    建议开题顺序:A->B->C->F->E->D诈骗差评,典题差评,想易写难数据结构差评。A.EverybodyLikesGoodArrays!好像是结论题,但是一力降十会。显然最后合并完后,每个......
  • P5030 题解
    前言题目传送门!更好的阅读体验?一道没啥意思的题目,但是好像很多题解都过不了现在的数据?思路只不过是把正常题目的马(\(1,2\))换成了另一种东西(\(1,3\))。很套路地,黑白......
  • 洛谷 P1123 取数游戏 (又是写了好久 最后还是无奈看了题解……)
    对于这个题感觉是一个比较典型的dfs.本题的状态是对于每个数字你可以选也可以不选,但是一旦你选定某个数字之后,他会对其周围的数字产生影响所以一定要标记好(注意这里标记的......
  • AT_abc286d 题解
    板子首先我们看到值域并不大。因此可以维护值域,跑完全背包。具体而言维护某一个值(小于\(10000\))是否能被凑出来,然后枚举物品种类以及物品数量即可。一般而言,完全背包......
  • AT_abc286e 题解
    首先观察到\(n\leq300\)加上全源“最短路”便可以自然而然的想到floyd。注意到floyd算法的可行性只依赖统计的东西具有优先级。这里我们定义优先级为最短路最短且......
  • ABC286 A-E题解
    题目虽然是大年三十,但是玩手机没写题有意思。从50分钟才开始看题。A题意:将数组中\([p,q]\)与\([r,s]\)的元素交换并输出。sbt。B大意:将字符中的na换成nya。......
  • AcWing 第87场周赛题解
    T1移动棋子算出为\(1\)的点离\((3,3)\)的距离即可。#include<iostream>#include<cstring>#include<algorithm>usingnamespacestd;intmain(){int......
  • LeetCode.面试题02.05-链表求和-题解分析
    题目来源面试题02.05.链表求和题目详情给定两个用链表表示的整数,每个节点包含一个数位。这些数位是反向存放的,也就是个位排在链表首部。编写函数对这两个整数求和,并......
  • Codeforces Round48 Edu题解
    A-DeathNote(模拟)题意​ 现在有一本书,每页可以写下\(m\)个数字,给你一个序列\(a\),依次在书上誊写\(a_i\)个数字,请问誊写序列的第\(i\)个数的时候书翻了几页?​ ......
  • HGAME 2023 Week2 Pwn YukkuriSay题解
    HGAME2023Week2PwnYukkuriSay题解检查保护:拿到文件先checksec一下:64位程序,开启canary和nx保护,没有开启PIE(可以使用绝对地址了)继续往下看,先不着急打开ida,我们先运......