zoukankan      html  css  js  c++  java
  • CF1156E Special Segments of Permutation

    CF1156E Special Segments of Permutation

    给定一个长度为 (n) 的排列,求有多少个区间 ([l, r]) 使得 (a_l+a_r=displaystylemax_{i=l}^r{a_i})

    (nleq2 imes10^5)

    单调栈,暴力,启发式合并


    考虑枚举每个数作为最大值出现的区间 ([l_i, r_i]) ,可以用单调栈 (O(n)) 求出

    对于区间 ([l_i, r_i]) ,考虑枚举左端点 (l) ,可以求出右端点元素 (a_r=a_i-a_l) ,若 (rin[i, r]) ,则计入贡献

    但这样是 (O(n^2))

    考虑一个看似无用的优化:每次枚举 ([l, i], [i, r]) 较短的一侧

    考虑这样的时间复杂度:对原排列建树,对区间 ([l, r]) 将区间最大值 (a_i) 作为根,两侧递归。这样点 (i) 所遍历的点数即为 (min(operatorname{size(lson), size(rson)})) ,可以采用启发式合并的时间复杂度证明

    时间复杂度 (O(nlog n))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 2e5 + 10;
    int n, top, a[maxn], st[maxn], pos[maxn], lef[maxn], rig[maxn];
    
    int main() {
      scanf("%d", &n);
      for (int i = 1; i <= n; i++) {
        scanf("%d", a + i), pos[a[i]] = i;
      }
      for (int i = 1; i <= n; i++) {
        while (top && a[st[top]] < a[i]) top--;
        lef[i] = st[top] + 1, st[++top] = i;
      }
      top = 0, st[0] = n + 1;
      for (int i = n; i; i--) {
        while (top && a[st[top]] < a[i]) top--;
        rig[i] = st[top] - 1, st[++top] = i;
      }
      int ans = 0;
      for (int i = 1; i <= n; i++) {
        int l = lef[i], r = rig[i];
        if (i - l < r - i) {
          for (int j = l; j <= i; j++) {
            ans += pos[a[i] - a[j]] >= i && pos[a[i] - a[j]] <= r;
          }
        } else {
          for (int j = i; j <= r; j++) {
            ans += pos[a[i] - a[j]] >= l && pos[a[i] - a[j]] <= i;
          }
        }
      }
      printf("%d", ans);
      return 0;
    }
    
  • 相关阅读:
    BOT、BT、PPP形式介绍(3)
    BOT、BT、PPP形式介绍(2)
    BOT、BT、PPP形式介绍(1)
    Linux系统下C++开发工具-远程终端软件使用
    Linux开发工具的使用
    libjingle开发人员指南
    优雅处理段错误
    捕捉段错误信号信号处理程序
    段错误bug的调试
    docker核心概念(镜像、容器、仓库)及基本操作
  • 原文地址:https://www.cnblogs.com/Juanzhang/p/11042187.html
Copyright © 2011-2022 走看看