【CF 1019(div 2) C】对顶堆失效?前缀和的进一步应用!
米娜桑好久(也就两个小时)不见!
现在带来的是CF 1019(div.2)的补题
最近就补C吧 D感觉比较难搞
如果补到最后能稳定出C就很棒了
我们先看题目
C.Median Splits
题目描述
数组 \(b_1, b_2, \ldots b_m\) 的中位数写为 \(\operatorname{med}(b_1, b_2, \ldots, b_m)\) ,是数组 \(b\) 中 \(\left\lceil \frac{m}{2} \right\rceil\) -th \(^{\text{∗}}\) 最小的元素。
给你一个整数数组 \(a_1, a_2, \ldots, a_n\) 和一个整数 \(k\) 。你需要确定是否存在一对索引 $ 1 \le l<r<n $ 这样的数组:
\(
\operatorname{med}(\operatorname{med}(a_1, a_2, \ldots, a_l), \operatorname{med}(a_{l+1}, a_{l+2}, \ldots, a_r), \operatorname{med}(a_{r+1}, a_{r+2}, \ldots, a_n)) \le k.
\)
换句话说,确定是否有可能将数组分割成三个连续的子数组,使得三个子数组的中位数小于或等于 \(k\) 。
\(^{\text{∗}}\) \(\lceil x \rceil\) 是ceil函数,返回大于或等于 \(x\) 的最小整数。
\(^{\text{†}}\) 一个数组 \(x\) 是一个数组 \(y\) 的子数组,如果 \(x\) 可以从 \(y\) 中删除开头的几个元素(可能是零或全部)和结尾的几个元素(可能是零或全部)。
输入
每个测试包含多个测试用例。第一行包含测试用例的数量 \(t\) ( \(1 \le t \le 10^4\) )。测试用例说明如下。
每个测试用例的第一行包含两个整数 \(n\) 和 \(k\) ( \(3 \le n \le 2 \cdot 10^5\) , \(1 \le k \le 10^9\) )--数组长度 \(a\) 和常数 \(k\) 。
每个测试用例的第二行包含 \(n\) 个整数 \(a_1, a_2, \ldots, a_n\) ( \(1 \le a_i \le 10^9\) ) - 数组 \(a\) 的元素。
保证所有测试用例中 \(n\) 的总和不超过 \(2 \cdot 10^5\) 。
输出
对于每个测试用例,如果存在分割,则输出 "YES",否则输出 "NO"。
您可以输出任何大小写的答案(大写或小写)。例如,字符串 "yEs"、"yes"、"Yes "和 "YES "将被识别为肯定回答。
样例输入
6
3 2
3 2 1
3 1
3 2 1
6 3
8 5 3 1 6 4
8 7
10 7 12 16 3 15 6 11
6 8
7 11 12 4 9 17
3 500000000
1000 1000000000 1000
样例输出
YES
NO
NO
YES
YES
YES
解法&&个人感想
我一开始想的是 用对顶堆 左右两个指针分别移动 然后模拟一下
感觉时间复杂度是对的?到现在也不知道为什么错
今天看了一下答案 先处理前缀和,这跟我当时做的很像
也就是说,我们把大于k的设置为-1.小于等于k的设置为1,题目转换成能否将其分割成三份,使得至少有两份的值大于等于0
如果左边和右边可分割 那当然很简单
这里细讲一下中间的怎么分割
我们维护一个前缀和的最大值
由于对称性 就考虑左边和中间满足条件
设左边的为 $ a_1,a_2,\ldots,a_r $ 右边的为 $ a_{r+1},a_{r+2},\ldots,a_n $
然后,我们看到这里的右边这段,如果存在一段使得和大于等于0,则右边的 $presum_{r+1},presum_{r+2}\ldots,presum_n \(
中必然存在一个\) presum_t $ ,使得 $ presum_t -presum_r \ge 0 $
现在,我们维护$ presum_{r+1},presum_{r+2},\ldots presum{n} $中的最大值,由上面的分析,这个最大值必然大于等于 $ presum_r $,所以,我们只需遍历 $ 1 \le i \le {n-2} $,如果有满足上述条件的就成立,反之不成立
如果是右侧加上中间同理
下面看代码:
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define maxn 200005
using namespace std;
int t,n,k;
int a[maxn];
const int INF=1e8;
int main(){
cin>>t;
while(t--){
cin>>n>>k;
vector<int>presum(n+5,0);
vector<int>premax(n+5,-INF);
vector<int>fpremax(n+5,-INF);
vector<int>fpresum(n+5,0);
for(int i=1;i<=n;i++){
cin>>a[i];
presum[i]=0;
if(a[i]>k) a[i]=-1;
else a[i]=1;
}
for(int i=1;i<=n;i++){
presum[i]=presum[i-1]+a[i];
}
for(int i=n;i>=1;i--){
fpresum[i]=fpresum[i+1]+a[i];
}
for(int i=n;i>=1;i--){
premax[i]=max(premax[i+1],presum[i]);
}
for(int i=1;i<=n;i++){
fpremax[i]=max(fpremax[i-1],fpresum[i]);
}
int l=1,r=n;
while(l<n-1){
if(presum[l]>=0) break;
l++;
}
while(r>2){
if(presum[n]-presum[r-1]>=0) break;
r--;
}
if(l+1<r){
printf("YES\n");
continue;
}
int flag=0;
for(int i=1;i<=n-2;i++){
if(presum[i]>=0&&premax[i+1]>=presum[i]){
flag=1;
break;
}
}
for(int i=n;i>=3;i--){
if(fpresum[i]>=0&&fpremax[i-1]>=fpresum[i]){
flag=1;
break;
}
}
if(flag) printf("YES\n");
else printf("NO\n");
}
return 0;
}
这篇打得有点累 因为一堆markdown公式不是很记得
后面应该还会开个坑 记录一下目前写博客常用的markdown语法
最近又到了白色相簿的季节,大家要妥善处理三角恋关系呀

后半学期,也请各位继续关注:
《我的青春线代物语果然有问题》
《高数女主养成计划》
《程设の旅》
《青春猪头少年不会梦到多智能体吃豆人》
《某Linux的开源软件》
还有——
《我的算法竞赛不可能这么可爱》
本期到此结束!

浙公网安备 33010602011771号