首页 > 其他分享 >AtCoder Beginner Contest 247 E - Max Min

AtCoder Beginner Contest 247 E - Max Min

时间:2022-10-27 23:03:19浏览次数:36  
标签:AtCoder Beginner Min int max min MID long ++

题目描述

简要描述:给定一个长度为 \(N\) 的数组,求数组的子数组满足最大值为 \(X\) 且最小值为 \(Y\) 的子区间的个数。

做法

1. ST表 + 二分

时间复杂度: \(O(n \log n)\)

对于每个位置,二分出以它为左端点最大值为 \(X\) 的最远和最近的位置,以及以它为左端点最小值为 \(Y\) 的最远和最近的位置,然后对两个区间求区间交即可统计答案

代码

点击查看代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

template <typename T> void chkmax(T &x, T y) { x = max(x, y); }
template <typename T> void chkmin(T &x, T y) { x = min(x, y); }

//使用的时候注意判断如果 多个最值 取左边下标还是右边下标
//分别对应 >= >   <= <
template<typename T> 
class ST{
  public:
  ST(vector<T> a, int _n) : a(a), n(_n) { // cope with in [0,n-1] 
    lg.resize(n + 1); lg[1] = 0; 
    for (int i = 2; i <= n; i ++ ) lg[i] = lg[i >> 1] + 1;
    int m = lg[n] + 1;
    maxv.resize(m); minv.resize(m);
    
    for (int i = 0; i < m; i ++ ) maxv[i].resize(n), minv[i].resize(n); 
    for (int i = 0; i < n; i ++ ) maxv[0][i] = minv[0][i] = a[i];

    for (int i = 1; i < m; i ++ ) {
      for (int j = 0; j <= n - (1 << i); j ++ ) {
        maxv[i][j] = max(maxv[i - 1][j], maxv[i - 1][j + (1 << (i - 1))]);
        minv[i][j] = min(minv[i - 1][j], minv[i - 1][j + (1 << (i - 1))]);
      }
    }

  }
  T getmax(int l,int r){
    int k = lg[r - l + 1];
    return max(maxv[k][l], maxv[k][r - (1 << k) + 1]);
  }    
  T getmin(int l,int r){
    int k = lg[r - l + 1];
    return min(minv[k][l], minv[k][r - (1 << k) + 1]);
  }    
private:
  int n;
  vector<T> a;
  vector<int> lg;
  vector<vector<T>> maxv, minv;
};


void solve() {
  int n, l, r; cin >> n >> r >> l;
  vector<int> a(n); for (int &x: a) cin >> x;
  ST st(a, n);
  ll ans = 0;
  for (int i = 0; i < n; i ++ ) if (a[i] >= l && a[i] <= r) {
    int L = i, R = n - 1;
    while (L < R) {
      int MID = (L + R + 1) / 2;
      if (st.getmax(i, MID) > r) R = MID - 1;
      else L = MID;
    }
    //此时的L就是最大值的右边界
    if (st.getmax(i, L) != r) continue;
    int maxr = L;
    L = i, R = R;
    while (L < R) {
      int MID = (L + R) / 2;
      if (st.getmax(i, MID) >= r) R = MID;
      else L = MID + 1;
    }
    int maxl = L;
    if (st.getmax(i, L) != r) continue;
    if (maxl > maxr) continue;

    L = i, R = n - 1;
    while (L < R) {
      int MID = (L + R + 1) / 2;
      if (st.getmin(i, MID) < l) R = MID - 1;
      else L = MID;
    }
    int minr = L;
    if (st.getmin(i, L) != l) continue;


    L = i, R = R;
    while (L < R) {
      int MID = (L + R) / 2;
      if (st.getmin(i, MID) <= l) R = MID;
      else L = MID + 1;
    }
    
    int minl = L;

    if (st.getmin(i, L) != l) continue;

    if (minl > minr) continue;

    if (minl > maxr || maxl > minr) continue;

    ans += min(maxr, minr) - max(maxl, minl) + 1;
  }

  cout << ans << "\n";

}
int main() {
  cin.tie(nullptr)->sync_with_stdio(false);
  solve();
  return 0;
}

2. 三指针

时间复杂度: \(O(n)\)

对于每个位置,统计以它为右端点的区间个数。只需要知道当前位置左边,距离它最近的且值为 \(X\) 的位置 \(i_1\),距离它最近的且值为 \(Y\) 的位置 \(i_2\) ,距离它最近的且不在区间 \([Y, X]\) 的位置 \(i_0\) ,然后个数就是 \(\max(0, min(i_1, i_2) - i_0)\)

代码

点击查看代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

class Solution {
 public:
  long long countSubarrays(vector<int> &nums, int min_k, int max_k) {
    long long ans = 0L;
    int n = nums.size(), min_i = -1, max_i = -1, i0 = -1;
    for (int i = 0; i < n; ++i) {
      int x = nums[i];
      if (x == min_k) min_i = i;
      if (x == max_k) max_i = i;
      if (x < min_k || x > max_k) i0 = i;  // 子数组不能包含 nums[i0]
      ans += max(min(min_i, max_i) - i0, 0);
    }
    return ans;
  }
};

void solve() {
  int n; cin >> n;
  int x, y; cin >> x >> y;
  vector<int> a(n); for (int &x: a) cin >> x;
  Solution s;
  cout << s.countSubarrays(a, y, x) << "\n";
}
int main() {
  cin.tie(nullptr)->sync_with_stdio(false);
  solve();
  return 0;
}

3. \(DP\)

时间复杂度: \(O(n)\)

定义 dp[i][j][k] 表示以 \(i\) 为右端点且状态为 \(j\) 和 \(k\) 的方案数。

第二维和第三维的 \(0 / 1\) 表示是否含最大值 或者 最小值

代码

点击查看代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

constexpr int N = 2E5 + 10;

int n, x, y;
int a[N], dp[N][2][2];

void solve() {
  cin >> n >> x >> y;
  for (int i = 1; i <= n; i ++ ) {
    cin >> a[i];
  }

  ll ans = 0;

  for (int i = 1; i <= n; i ++ ) {
    if (a[i] > x || a[i] < y) continue;
    bool fx = a[i] == x;
    bool fy = a[i] == y;
    dp[i][fx][fy] ++;
    for (int p = 0; p < 2; p ++ ) {
      for (int q = 0; q < 2; q ++ ) {
        dp[i][p | fx][q | fy] += dp[i - 1][p][q];
      }
    }
    ans += dp[i][1][1];
  }

  cout << ans << "\n";

}

int main() {
  cin.tie(nullptr)->sync_with_stdio(false);
  solve();
  return 0;
}


标签:AtCoder,Beginner,Min,int,max,min,MID,long,++
From: https://www.cnblogs.com/c972937/p/16834327.html

相关文章

  • new: 轮播图 | MDN上HTML的总结和CSS面试题解答,以及vue-admin/豆瓣一个静态页面的实现
    主要参看oppo官网https://www.oppo.com/cn/,实现以下功能一、轮播图https://www.cnblogs.com/WindrunnerMax/p/12638005.html通常是在首页读秒播放的图片,本次了解的是opp......
  • vue-element-admin框架学习笔记
    0背景vue-element-admin是一个已高度完成的系统原型,它基于vue框架和elementUI组件库。它使用最新的前端技术栈,内置i18n国际化解决方案、动态路由、权限验证。它可以帮助......
  • 安装minikube
    https://minikube.sigs.k8s.io/docs/start/1、下载https://storage.googleapis.com/minikube/releases/latest/minikube-installer.exe2、安装运行cmd-->minikubes......
  • Ubuntu 安装 PhpMyAdmin 管理 MySQL 数据库
     Ubuntu安装PhpMyAdmin管理MySQL数据库前言:当前服务器有跳板机不能直接用本地navicat连接数据库问题  PhpMyAdmin是一个用PHP编写的软件工具,可以通过......
  • LeetCode_Array_64. Minimum Path Sum (C++)
    目录​​1,题目描述​​​​2,思路​​​​3,代码【C++】​​​​4,测试效果​​1,题目描述Givenamxngridfilledwithnon-negativenumbers,findapathfromtopleftt......
  • MINGW64 禁用 Bash 路径参数转换
    MINGW64可以让Windows无缝使用Linux命令,但是路径参数会被转换为Windows风格。例如:$./adbshellls/systemls:C:/Program:Nosuchfileordirectoryls:Fil......
  • AtCoder Beginner Contest 266 Ex Snuke Panic (2D)
    AtCoder传送门洛谷传送门考虑dp,\(f_i\)设在\(t_i\)时刻到达第\(i\)个点,能获得的最大收益。转移:\(f_i=f_j+a_i\),其中\(j\)能转移到\(i\)的充要条件有:\(......
  • Java Annotation注解总结 ,注解有多个属性使用 @Check(min=0, max=100, value=55)
    JavaAnnotation注解总结注解有多个属性使用@Check(min=0,max=100,value=55)使用注解注解是放在Java源码的类、方法、字段、参数前的一种特殊“注释”。注解则......
  • AtCoder Beginner Contest 201 题解
    vp情况:过了A到E,F没时间也不会。vp总结:ABC表现可以。D慢了一点,写之前大概考虑清楚每个变量或函数的意义,结构明晰才能更快的写出代码。E花的时间太长,原因......
  • [HCTF 2018]admin 1
    [HCTF2018]admin1<文章中有有关flasksession文章需要认真读一下>1.信息搜集由题意,注册admin用户,回显Theusernamehasbeenregistered猜测需要去伪造admin......