Max Median题解

开始的解题思路:
1.直接对区间进行二分(这个肯定不行,因为区间不单调且k不固定,这样的话,每找一次就要再排序一次,又要恢复状态,必然超时)
2.二分查找中点值(本题的话left、right和mid必然为整数,这就减少了不少麻烦)
障碍:什么是二分条件(用什么判断该中点值是小了还是大了)
C题用过前缀和,所以的话现在我也想的是能不能用前缀和,上一题是如果找到一段区间和大于等于0,那么就说明当前的平均值依然有扩大的可能。但是这题的话找的是中位数,判断一个中位数在一段区间内是否存在,可以在一开始输入时利用桶排,把已经有的都给标记上,然后判断是否有这个中位数。(但是如何判断是往小了搜还是往大了搜呢?)

分为两种可能:
1.当前mid这一中位数在区间内是客观存在的,这种情况最好,满足条件就提left,不满足降低right
2.当前mid是不存在的,那么就存在一个问题,如何升降左右两边呢?
暂时的解决方法(AC思路):,将他自己和比他大的全部设为1,比他小的全部设为-1(找中位数和数值本身大小没太大关系,中位数左右边数的顺序其实没有太大关系),然后看看区间和,如果区间和大于0,说明仍然有把数往上提的空间,如果小于0,说明太大了,要降低一点。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
int n,k;
bool f[200050];
int num[200050],temp[200050];
int jud(int a,int b){(建立一个函数返回1-1,如上所说)
	if(a>=b)return 1;
	 else if(a<b) return -1;
}
void ready(int cur){
	int i;
	for(i=1;i<=n;i++){(前缀和初始化)
	 	num[i]=jud(num[i],cur);
	 	num[i]+=num[i-1];
    }
}
bool check(int kk){
	int sum1=num[k-1],sum2=0,i;(找区间和)
	for(i=k;i<=n;i++){
		sum2=num[i]-num[i-k];
		sum1+=jud(temp[i],kk);
		sum1=max(sum1,sum2);
		if(sum1>0) 
		 return 1;
	}
	return 0;
}
void reset(){
	int i;
    for(i=1;i<=n;i++)
      num[i]=temp[i];
}
int main(){
	memset(f,0,sizeof(f));
	scanf("%d%d",&n,&k);
	int i;
	int left=200050,right=0,mid;
	num[0]=0;
	for(i=1;i<=n;i++){
		scanf("%d",&num[i]);
		temp[i]=num[i];
		left=min(left,num[i]);
		right=max(right,num[i]);
		f[num[i]]=1;(桶排标记其是否存在)
	}
	
	if(k==n||k==1){(特判两个)
		sort(num+1,num+n+1);
		if(k==n)
		printf("%d",num[(1+n)/2]);
		 else printf("%d",num[n]);
		return 0;
	}
	
	while(left<right){
		mid=ceil(double((left+right))/2);(按照最大值来判断)
		ready(mid);
		if(check(mid)){
			if(f[mid])(判断是否有这个数,有的话就是它了,它可能就是答案,没有的话就+1,往下找找)
		    left=mid;
		     else left=mid+1;
	    }
		else right=mid-1;
		reset();
	}
	printf("%d",right);
}

总结:这题在区间处理那里要注意,这种题目的大概有两个套路,直接二分区间或者是二分答案,但是二分的条件是个难点,需要好好找找。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值