Codeforces Round 1019 (Div. 2) C题

题目链接

Codeforces Round 1019 (Div. 2) C题

写在前面

补题时这题完全没有思路,看了别人的思路才发现这题挺巧妙的,动态中位数可以用前缀和来求解,之前我一直没做过这类型的题目,遇到这题直接懵了,其实代码挺简单的,主要是要想到如何用前缀和求动态中位数,也是学到新知识了QWQ

题意

把数组分成三段,使得三段的中位数组成的数组的中位数小于等于 k k k

思路

显然我们要满足题目要求,那最终这三段序列一定满足下列条件之一:

  • 有 无 有
  • 有 有 无
  • 无 有 有

(有:中位数小于等于 k k k,无:中位数大于 k k k

接下来考虑如何枚举满足的子序列,我们可以用前缀和求动态中位数

如果 a i < = k , 它的贡献为 1 ,反之它的贡献为 0 a_i<=k,它的贡献为1,反之它的贡献为0 ai<=k,它的贡献为1,反之它的贡献为0 ,然后用一个前缀数组 p r e pre pre,后缀数组 s u f suf suf 累加
i f ( p r e [ i ] > = ( i + 1 ) / 2 ) if(pre[i]>=(i+1)/2) if(pre[i]>=(i+1)/2) 满足,将下标存入 l l l 数组,后缀数组同理

接下来考虑上述的3种情况

  • l . s i z e ( ) > 2 l.size()>2 l.size()>2则这个序列一定满足:有 有 无
  • r . s i z e ( ) > 2 r.size()>2 r.size()>2则这个序列一定满足:无 有 有
  • l . f r o n t ( ) + 1 < r . f r o n t ( ) l.front()+1<r.front() l.front()+1<r.front() l l l数组最小的下标和 r r r数组最大的下标如果不相邻,则这个序列一定满足:有 无 有
  • l . s i z e ( ) = 2 l.size()=2 l.size()=2 r . s i z e ( ) = 2 r.size()=2 r.size()=2 需要特判,判断中间的序列的中位数是否小于等于 k k k
  • 都不满足,输出NO

code

void solve(){
	int n,k;
	cin >> n >> k;
	for(int i=1;i<=n;++i) cin >> a[i];
	vector<int> pre(n+5),suf(n+5),l,r;
	for(int i=1;i<=n;++i) pre[i]+=pre[i-1]+(a[i]<=k);
	for(int i=n;i>=1;--i) suf[i]+=suf[i+1]+(a[i]<=k);
	for(int i=1;i<=n;++i){
		if(pre[i]>=(i+1)/2) l.push_back(i);
	}
	for(int i=n;i>=1;--i){
		int x=n-i+1;
		if(suf[i]>=(x+1)/2) r.push_back(i);
	}
	if(l.size()>2 || r.size()>2){
		cout << "YES" << endl;
		return ;
	} 
	if(l.size() && r.size() && l.front()+1<r.front()){
		cout << "YES" << endl;
		return ;
	}
	if(l.size()==2){
		if(pre[l[1]]-pre[l[0]]>=(l[1]-l[0]+1)/2){
			cout << "YES" << endl;
			return ;
		} 
	}
	if(r.size()==2){
		if(suf[r[1]]-suf[r[0]]>=(r[0]-r[1]+1)/2){
			cout << "YES" << endl;
			return ;
		} 
	}
	cout << "NO" << endl;
	return ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值