二分AtcoderE - Max Min
Posted 行码棋
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二分AtcoderE - Max Min相关的知识,希望对你有一定的参考价值。
https://atcoder.jp/contests/abc247/tasks/abc247_e
题意:给定一个序列,求一个 序列中满足条件的子数组个数
条件:数组中的最大值为x,最小值为y
注意初始化 f 1 [ i ] , f 2 [ i ] f1[i],f2[i] f1[i],f2[i]数组
f
1
[
i
]
f1[i]
f1[i]:代表左边离i
位置最近的最大值的位置
f
2
[
i
]
f2[i]
f2[i]:代表左边离i
位置最近的最小值的位置
c n t [ i ] cnt[i] cnt[i]:代表区间 [ 1 , i ] [1,i] [1,i]满足在最大值和最小值之间的数的个数(就是一个前缀和,记录的是最大最小值之间的个数)
二分
对于每一个固定的右端点i
,找左边最近的最大值和最小值的位置,一个合法的区间之中必然至少包含一个最大值和一个最小值,所以两个位置去min
操作。
假设这个最小的位置为
p
=
m
i
n
(
f
1
[
i
]
,
f
2
[
i
]
)
p = min(f1[i], f2[i])
p=min(f1[i],f2[i])
查找过程有两种情况:
-
[
p
,
i
]
[p,i]
[p,i]之中可能有小于最小值或者大于最大值的数,
c
n
t
[
i
]
−
c
n
t
[
p
−
1
]
!
=
i
−
p
+
1
cnt[i] - cnt[p - 1] != i - p + 1
cnt[i]−cnt[p−1]!=i−p+1则之间有不满足情况的数,所以以
i
为右端点的区间就不能够计算 - p = 0 p=0 p=0,说明就根本找不到最大值或者最小值,肯定不满足
找到P之后进行二分
p
位置之后最小可以满足的区间左端点的最右边,我们还要看是否能够向左扩展
根据 c n t [ ] cnt[] cnt[]的性质进行二分:
答案res
右边满足cnt[p] - cnt[res - 1] == p - res + 1
,左边不满足,根据此性质二分
#include<bits/stdc++.h>
using namespace std;
using ll = long long ;
using pii = pair<int, int>;
const int N = 250005, mod = 998244353;
int a[N], f1[N], f2[N], cnt[N];
void solve()
int n, mx, mn;
cin >> n >> mx >> mn;
ll res = 0;
for(int i = 1; i <= n; i++)
cin >> a[i];
if(a[i] == mx) f1[i] = i;
else f1[i] = f1[i - 1];
if(a[i] == mn) f2[i] = i;
else f2[i] = f2[i - 1];
cnt[i] = cnt[i - 1] + (a[i] >= mn and a[i] <= mx ? 1 : 0);
int p = min(f1[i], f2[i]);
if(p == 0 || cnt[i] - cnt[p - 1] != i - p + 1) continue;
int l = 1, r = p;
while(l < r)
int mid = (l + r) >> 1;
if(cnt[i] - cnt[mid - 1] == i - mid + 1) r = mid;
else l = mid + 1;
res += p - l + 1;
cout << res << "\\n";
int main()
ios::sync_with_stdio(false);
cin.tie(0);
int t;
// cin >> t;
t = 1;
while(t--)
solve();
return 0;
以上是关于二分AtcoderE - Max Min的主要内容,如果未能解决你的问题,请参考以下文章
ABC215 F - Dist Max 2(二分,排序降维,双指针)