2022-08-26 QLUACM暑假训练5 I题题解

这篇博客介绍了如何利用中位数和前缀和的性质来解决一个经典的信息技术问题——寻找二位偏序的区间数量。作者首先通过二分查找确定合适的中位数,并将数组元素设为1或-1,接着利用前缀和快速计算区间和。然后通过归并排序处理区间,检查是否存在满足条件的区间,最终得出解决方案。该方法适用于处理大数据集,具有较高的效率。
摘要由CSDN通过智能技术生成

D - Median of Medians (atcoder.jp)

中位数和平均数都有01串的性质,所以我们可以先二分答案mid,找到有哪些数大于等于mid设为1,哪些数小于mid设为-1,然后找哪些区间有至少n/2个正数即转变成了和大于等于0的区间有多少个,那么自然想到要用前缀和处理一下,这样可以o1内查询一段区间的和。然后就转变成了一个经典的二位偏序的题目——即x<y且sum[x]<=sum[y]的区间有多少个,即可利用树状数组或者归并排序的做法解决。

#include<bits/stdc++.h>
#define PII pair<int,int>
#define PLL pair<long long,long long>
#define fi first
#define se second
#define endl '\n'
#define bug printf("bug\n");
using namespace std;
const int N=2e5+10;
const int INF=0x3f3f3f3f;
const long long LNF=0x3f3f3f3f3f3f3f3f;
const long long mod=1e9+7;
long long n;
long long s[N],st[N],sum[N];
long long res=0,num=0;

void mergesort(long long l,long long r){
    if(l==r) return ;
    long long mid=(l+r)>>1;
    mergesort(l,mid);  mergesort(mid+1,r);
    long long v1=l,v2=mid+1,cnt=l;
    while(v1<=mid&&v2<=r){
        if(sum[v1]<sum[v2]) st[cnt++]=sum[v1++];
        else res=res+(v1-l),st[cnt++]=sum[v2++];
    }
    while(v1<=mid) st[cnt++]=sum[v1++];
    while(v2<=r) res=res+(v1-l),st[cnt++]=sum[v2++];
    for(long long i=l;i<=r;i++) sum[i]=st[i];
}

bool check(int mid){
	res=0;
	for(int i=1;i<=n;i++){
		if(s[i]<=mid) sum[i]=1;
		else sum[i]=-1;
	}
	for(int i=1;i<=n;i++) sum[i]=sum[i-1]+sum[i];
	//for(int i=1;i<=n;i++) printf("%d ",sum[i]); puts("");
	mergesort(0,n);
	//printf("%d %d\n",mid,res);
	return res>=num/2+1;
}

void solve(){
	scanf("%lld",&n);
	for(int i=1;i<=n;i++) scanf("%lld",&s[i]);
	long long l=INF,r=0;
	for(long long i=1;i<=n;i++){
		l=min(l,s[i]); r=max(r,s[i]);
	}
	num=(n+1)*n/2;
	//printf("%lld\n",num);
	//printf("%d %d\n",l,r);
	while(l<r){
		long long mid=(l+r)>>1;
		if(check(mid)) r=mid;
		else l=mid+1;
	}
	printf("%lld\n",l);
}

int main(){
	int t=1;
	//scanf("%d",&t);
	while(t--){
		solve();
	}
	return 0 - 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值