版权声明:本文为博主原创文章,未经博主允许不得转载,欢迎前往zory.cf获得最佳体验 https://blog.csdn.net/Zory_Programmer/article/details/82077612
题意:给一个长度为
的数列,把每个子串的中位数组成新的序列,求其中位数
做法1:枚举
和
,然后排序组成中位数,时间复杂度
做法2:枚举
,再枚举
和
,统计比它小的数量考虑其贡献,时间复杂度
正解(大小逻辑关系的运用不一定完全相同):
1. 二分答案,难点在于如何判定问题:答案是否
2. 不难想到,可以判定
的数字,其贡献
,对于每个区间,用类似的思路,考虑是否会被”堵住“,
,用前缀和优化一下,
,为了方便,
3. 现在看起来复杂度是
,但是显然可以用数据结构如树状数组优化,变成
细节:爆int,一开始完全没注意到
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
namespace mine
{
const int MAXN=110000;
int n;
int tr[2*MAXN];
int lowbit(int x) {return x&-x;}
void change(int d)
{
d+=MAXN;
while(d<2*MAXN) tr[d]++,d+=lowbit(d);
}
int sum(int d)
{
d+=MAXN;
int ans=0;
while(d>=1) ans+=tr[d],d-=lowbit(d);
return ans;
}
int a[MAXN],b[MAXN];
int c[MAXN];
typedef long long ll;//debug 爆int
bool check(int now)
{
for(int i=1;i<=n;i++) c[i]=c[i-1]+(a[i]<=now?1:-1);//1小于等于,-1大于
memset(tr,0,sizeof tr);//debug
change(c[0]);//debug
ll tot=0;//<=now的数,产生的贡献
for(int r=1;r<=n;r++)
{
//c[r]-c[l-1]>0 => c[l-1]<c[r] (l-1<r)
tot+=sum(c[r]-1);
change(c[r]);
}
return tot>=ll(n+1)*n/4+1;
}
void main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
int l=1,r=1e9,ans=-1;
while(l<=r)
{
int mid=(l+r)/2;
if(check(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
printf("%d",ans);
}
};
int main()
{
mine::main();
}