二分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[p1]!=ip+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的主要内容,如果未能解决你的问题,请参考以下文章

[javaSE] 数组(查找-二分查找)

ABC215 F - Dist Max 2(二分,排序降维,双指针)

python--算法--中二分查询

Codeforces Round #361 (Div. 2)

有序数组二分法查找

[HDOJ5289]Assignment(RMQ,二分)