题解:P13091 中位数
思路
显然的,如果可以最终答案为
考虑二分答案,则需要判断是否可以使答案
将原数组转化为一个
相邻数才能合并,所以需要维护一个栈,依次从栈顶加入元素进行处理。
对于连续三个数消去的情况进行分类讨论:
- 三个数为
000 ,删去后变为0 ,减少两个0 ,故删去一定不劣。 - 三个数为
001 ,010 ,011 ,100 ,101 ,110 六种情况,可以发现此类情况删去后数列中1 和0 减少数量相同,故最后需要比较两者数量多少判断情况可行性,谁多剩下谁。 - 三个数为
111 ,删去少两个1 一定不优,不删等待后续计算。
根据以上结论
但是此时直接使用结论
所以对于
然后根据比较合并后整个序列中
还有别忘了多测清空。
代码实现
代码不长,私以为我的码风还是比较朴素正统的,可读性较强,应该方便理解。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int x[100005],y[100005],Q[100005],tail=0,n;
bool check(int u){
tail=0;
for(int i=1;i<=n;i++){
if(x[i]>=u)y[i]=1;
else y[i]=0;
}
for(int i=1;i<=n;i++){
if(tail>1&&Q[tail]==0&&Q[tail-1]==0)tail--;//001 和 000 的前缀都是 00 就合并处理了
else Q[++tail]=y[i];
}
int summ=0;
for(int i=1;i<=tail;i++){
if(Q[i]==1)summ++;
else summ--;
}//统计数目遇 0 减一,遇 1 加一,总数为正则 1 比 0 多
return summ>0;//长度奇数不存在总和为 0
}
signed main(){
int T;
scanf("%lld",&T);
while(T--){
scanf("%lld",&n);
for(int i=1;i<=n;i++)scanf("%lld",&x[i]);
int l=1,r=1e9;
while(l<r){
int mid=(l+r+1)/2;
if(check(mid))l=mid;
else r=mid-1;
}
printf("%lld\n",l);
}
return 0;
}