ABC 247 | E - Max Min

题目描述

给定一个长度为\(N\)的序列\(A = (A_1, A_2, A_3, ...,A_N)\)和两个数\(X, Y\),求满足以下条件的\((L, R)\)的个数。

  • \(1 \le L \le R \le N\)
  • \(A_L, A_{L + 1}, ...,A_{R}\)的最大值为\(X\),最小值为\(Y\)

数据范围

  • \(1 \le N \le 2 \times 10^5\)
  • \(1 \le A_i \le 2 \times 10^5\)
  • \(1 \le Y \le X \le 2 \times 10^5\)

解题思路

该题为计数题,可以在\(O(N^3)\)的时间复杂度内被暴力解决,由于数据范围为\(2 \times 10^5\),考虑对算法进行优化。
观察到题目的给出的条件发现:符合条件的序列中不会包含大于\(X\)和小于\(Y\)的数,故考虑以这些数为分界线划分数组,然后对其中的每一个子段求符合条件的序列个数。
这些子段中的\(A_i\)满足\(Y \le A_i \le X\),故寻找最大值为\(X\)且最小值为\(Y\)的序列等价于寻找包含\(X\)且包含\(Y\)的序列,符合条件的序列可以通过双指针算法在\(O(L)\)复杂度内求得,\(L\)为该段序列长度。故对于整个数组长度为\(N\)的序列,时间复杂度为\(O(N)\)

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long ll;

const int N = 2e5 + 10;

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

ll calc(int st, int ed){
    ll ans = 0, cntx = 0, cnty = 0;
    for(int l = st, r = st; l < ed; l ++){
        while(!(cntx && cnty) && r < ed){
            if(a[r] == x) cntx ++;
            if(a[r] == y) cnty ++;
            r ++;
        }
        if(cntx && cnty) ans += (ed - r + 1);
        if(a[l] == x) cntx --;
        if(a[l] == y) cnty --;
    }
    return ans;
}

int main()
{
    scanf("%d%d%d", &n, &x, &y);
    for(int i = 0; i < n; i ++) scanf("%d", &a[i]);

    ll ans = 0;
    for(int i = 0; i < n; ){
        int l = i;
        while(i < n && a[i] <= x && a[i] >= y) i ++;
        if(i > l) ans += calc(l, i);
        i ++;
    }
    printf("%lld\n", ans);
    return 0;
}

posted @ 2022-06-10 10:31  小菜珠的成长之路  阅读(44)  评论(0)    收藏  举报