AtCoder Regular Contest 101 (ARC101) D - Median of Medians 二分答案 树状数组

原文链接https://www.cnblogs.com/zhouzhendong/p/ARC101D.html

题目传送门 - ARC101D

题意

  给定一个序列 A 。

  定义一个序列 A 的中位数为:给 A 排序,得到的第 $\left\lfloor\cfrac{i}{2}\right\rfloor+1$ 项的值。

  序列 B 由序列 A 的所有连续子序列的中位数构成。

  问序列 B 的中位数是多少。

  序列中可能出现重复的数,$|A| \leq 10^5$ 。

题解

  注意这里说的“中位数”是题意里面定义的“中位数”。

  首先考虑二分答案。

  对于一个数 $k$ ,我们考虑判断最终序列的中位数是否 大于等于 $k$。

  考虑将原序列中 大于等于 $k$ 的数全部设置为 $1$,小于 $k$ 的数设为 $-1$ 。那么,如果一个序列的和 非负,它原来的中位数就必然大于等于 $k$ 。

  考虑用树状数组统计出中位数大于等于 $k$ 的序列个数 $ans$ 。

  如果 $ans\geq \cfrac{n(n+1)}4$ ,那么显然,序列 B 的中位数大于等于 $k$ 。

  于是就可以在 $O(n\log^2 n)$ 的时间复杂度内解决这个问题了。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=200005;
int n,a[N],Ha[N],hs,k,f[N];
struct BIT{
	int n,c[N];
	void set(LL _n){
		n=_n;
		memset(c,0,sizeof c);
	}
	void add(int x,int d){
		for (;x<=n;x+=x&-x)
			c[x]+=d;
	}
	int ask(int x){
		int ans=0;
		for (;x;x-=x&-x)
			ans+=c[x];
		return ans;
	}
}T;
bool check(int k){
	for (int i=1;i<=n;i++)
		f[i]=f[i-1]+(a[i]>=k?1:-1);
	T.set(n*2+1);
	LL ans=0;
	for (int i=0;i<=n;i++){
		ans+=T.ask(f[i]+n+1);
		T.add(f[i]+n+1,1);
	}
	return ans>=1LL*n*(n+1)/4;
}
int main(){
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
		scanf("%d",&a[i]),Ha[i]=a[i];
	sort(Ha+1,Ha+n+1);
	hs=unique(Ha+1,Ha+n+1)-Ha-1;
	for (int i=1;i<=n;i++)
		a[i]=lower_bound(Ha+1,Ha+hs+1,a[i])-Ha;
	int L=1,R=hs,mid,ans=L;
	while (L<=R){
		mid=(L+R)>>1;
		if (check(mid))
			L=mid+1,ans=mid;
		else
			R=mid-1;
	}
	printf("%d",Ha[ans]);
	return 0;
}

  

转载于:https://www.cnblogs.com/zhouzhendong/p/ARC101D.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值