Codeforces D. Max Median (二分+思维)

题目链接

题意:给出你一个长度为n的序列,让你求长度最小为k的中位数的最大值。 1 < = a i < = n 1<=a_i<=n 1<=ai<=n
题解:首先我们通过数据范围可以看出,完全可以二分来做,左端是1,右端是n,其次我们看中位数,就是大于他的数比小于他的数一样多或者多一个。所以我们可以假设数组中只有两种元素,一种是比x小的我们定值为-1,另一种我们定值为1,这样,为了平衡-1与1,最终让他们处于一个平衡的状态,我们可以看出,如果存在一个范围值大于0,那么就说明中位数可以再大一点,如果没有那么我们就需要减小这个值,所以我们就找到了单调性。
这样我们维护一个前缀和,然后只需要判断是不是存在区间长度≥k的区间和为正数即可。
只需要维护一个前缀和的前缀最小值,然后枚举当前为区间终点,前缀最小值的位置为起点即可。

有必要说一下infac数组,它的用途是为了减去前缀小于0的那部分,就是从最小的后面开始。

#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
#include <immintrin.h>
#pragma GCC optimize(2)
#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
typedef pair<ll,ll> pii;
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define mem(a,x) memset(a,x,sizeof(a))
#define debug(x) cout << #x << ": " << x << endl;
#define rep(i,n) for(int i=0;i<(n);++i)
#define repi(i,a,b) for(int i=int(a);i<=(b);++i)
#define repr(i,b,a) for(int i=int(b);i>=(a);--i)
const int maxn=2e5+1010;
#define inf 0x3f3f3f3f
#define sf scanf
#define pf printf
const int mod=998244353;
const int MOD=10007;

inline int read() {
    
    
    int x=0;
    bool t=false;
    char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}

/*
vector<ll> m1;
vector<ll> m2;
priority_queue<ll , vector<ll> , greater<ll> > mn;//上  小根堆 		小到大
priority_queue<ll , vector<ll> , less<ll> > mx;//下   	大根堆  	大到小
map<ll,ll>mp;*/
ll n;
ll a[maxn],k;
ll fac[maxn];
ll infac[maxn];
ll qpow(ll a,ll b) {
    
    
    ll sum=1;
    while(b) {
    
    
        if(b&1) sum=sum*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return sum;
}
bool check(ll x){
    
    
    for(int i=1;i<=n;i++){
    
    
        if(a[i]>=x){
    
    
            fac[i]=fac[i-1]+1;///判断这个数是大于他的多还是小于他的多
        }else {
    
    
            fac[i]=fac[i-1]-1;
        }
        infac[i]=min(infac[i-1],fac[i]);///最多可加的
    }
    for(int i=k;i<=n;i++){
    
    
        if(fac[i]-infac[i-k]>0) return 1;
    }
    return 0;
}
#define read read()
int main() {
    
    
    cin>>n>>k;
    for(int i=1;i<=n;i++){
    
    
        scanf("%lld",&a[i]);
    }
    ll l=1,r=n,ans=0;
    while(l<=r){
    
    
        ll mid=(l+r)/2;
        if(check(mid)){
    
    
            ans=mid;
            l=mid+1;
        }else {
    
    
            r=mid-1;
        }
    }
    cout<<ans<<endl;
    return 0;
}


猜你喜欢

转载自blog.csdn.net/weixin_45911397/article/details/114239682