文章目录
- 题目链接
- 写在前面
- 题意
- 思路
- code
题目链接
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 ;
}