码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2018-09-02 21:42:22      阅读:193      评论:0      收藏:0      [点我收藏+]

标签:memset   一个   class   rac   ++   highlight   tps   复杂   链接   

原文链接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;
}

  

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

标签:memset   一个   class   rac   ++   highlight   tps   复杂   链接   

原文地址:https://www.cnblogs.com/zhouzhendong/p/ARC101D.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!