題目描述
分析
之前做過類似的兩道題,一道是區間和的\(k\)小值,一道是眾數的\(k\)小值
那兩道統計的東西都有單調性,可以用兩個指標維護,\(O(n)\)計算
但是平均數沒有單調性,不能用兩個指標去掃
但是這道題的資料範圍是 \(10^5\),時間限制是\(2.5s\)
統計答案時還可以再套一個\(log\)
如果當前列舉的平均值是\(mid\)的話
我們只需要找出所有\(\frac{sum[j]-sum[i]}{j-i} \leq mid\)的數對即可
我們把分母乘過去,就變成了\(sum[i]-mid \times i \geq sum[j]-mid \times j\)
可以看成區間求逆序對
用樹狀陣列做需要離散化,用歸併排序比較方便
程式碼
#include<cstdio>
#include<queue>
#include<algorithm>
typedef double db;
const int maxn=1e6+5;
const db eps=1e-6;
int n,a[maxn];
long long sum[maxn],m,js;
db b[maxn],c[maxn];
void msort(int l,int r){
if(l==r) return;
int mids=(l+r)>>1;
msort(l,mids);
msort(mids+1,r);
int now=l,t=l-1;
for(int i=mids+1;i<=r;i++){
while(b[now]<b[i] && now<=mids){
c[++t]=b[now++];
}
js+=mids-now+1;
c[++t]=b[i];
}
while(now<=mids) c[++t]=b[now++];
for(int i=l;i<=r;i++) b[i]=c[i];
}
bool jud(db mids){
for(int i=0;i<=n;i++){
b[i]=sum[i]-i*mids;
}
js=0;
msort(0,n);
if(js>=m) return 1;
else return 0;
}
int main(){
freopen("ave.in","r",stdin);
freopen("ave.out","w",stdout);
scanf("%d%lld",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++){
sum[i]=sum[i-1]+a[i];
}
double l=-1e9,r=1e9,mids;
while(r-l>eps){
mids=(l+r)/2.0;
if(jud(mids)) r=mids;
else l=mids;
}
printf("%.4f\n",mids);
return 0;
}