1. 程式人生 > >雜題集萃[2]

雜題集萃[2]

include 偶數 () i++ main 表示 ans 得到 clu

中位數

題目描述

小N得到了一個非常神奇的序列A。

這個序列長度為N,下標從1開始。

A的一個子區間對應一個序列,可以由數對[l,r]表示,代表A[l], A[l + 1], ..., A[r]這段數。

對於一個序列B[1], B[2], ..., B[k],定義B的中位數如下:

  1. 先對B排序。得到新的序列C。

  2. 假如k是奇數,那麽中位數為。假如k為偶數,中位數為。

對於A的所有的子區間,小N可以知道它們對應的中位數。

現在小N想知道,所有長度>=Len的子區間中,中位數最大可以是多少。

輸入描述:

第一行輸入兩個數N,Len。

第二行輸入序列A,第i個數代表A[i]。

輸出描述:

一行一個整數,代表所有長度>=Len的子區間中,最大的中位數。

  • 輸入

11 3
4864 8684 9511 8557 1122 1234 953 9819 101 1137 1759 
  • 輸出

8684

數據範圍:

30%: n <= 200
60%: n <= 2000
另外有20%:不超過50個不同的數
100%:1<=Len<=n<=10^5, 1 <= a[i] <= 10^9

題解

二分前綴和

code

#include<iostream>
#include<cstdio>
using namespace std;
const int N=100010;
int n,m,i,j,k,a[N],b[N],t,l,r,mid;
bool f(int k){
    for (int i=1;i<=n;i++) if (a[i]<k) b[i]=-1; else b[i]=1;
    for (int i=1;i<=n;i++) b[i]+=b[i-1];
    int ans=b[m];t=0;
    for (int i=m+1;i<=n;i++){
        t=min(t,b[i-m]);
        ans=max(ans,b[i]-t);
    }
    if (ans>0) return true; 
    else return false;
}
int main(){
    scanf("%d%d",&n,&m);
    for (i=1;i<=n;i++) scanf("%d",&a[i]);
    l=1;r=1000000000;while (l<r){
        mid=(l+r)/2+1;
        if (f(mid)) l=mid; 
        else r=mid-1;
    }
    printf("%d\n",l);
    return 0;
}

雜題集萃[2]