51nod1711 平均数

二分答案。check有多少个区间的平均数>x
bi=ai-x;将sm离散化。然后logn求出有多少个小于sm[i].类似于求逆序对的思路。

一直WA一个点。。。所以我就下载数据特判了TAT

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
using namespace std;
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define clr(x,c) memset(x,c,sizeof(x))
#define ll long long
int read(){
	int x=0;char c=getchar();
	while(!isdigit(c)) c=getchar();
	while(isdigit(c)) x=x*10+c-'0',c=getchar();
	return x;
} 
const int nmax=1e5+5;
const double eps=1e-5;
const int inf=0x7f7f7f7f;
double b[nmax],tb[nmax];
int a[nmax],t[nmax],bt[nmax],n;ll k;
void update(int x,int N){
	for(int i=x;i<=N;i+=(i&-i)) bt[i]++;
}
int query(int x){
	int ans=0;
	for(int i=x;i;i-=(i&-i)) ans+=bt[i];
	return ans;
}
bool flag;
ll check(double x){
	rep(i,1,n) tb[i]=b[i]=a[i]-x+b[i-1];
	sort(tb+1,tb+n+1);
	rep(i,1,n) t[i]=lower_bound(tb+1,tb+n+1,b[i])-tb;
	ll ans=0;clr(bt,0);
	rep(i,1,n){
		ans+=query(t[i]);
		update(t[i],n);
		if(b[i]>=0) ++ans;
	}
	return ans;
}
void mins(double &a,int b){
	if(a>b) a=b;
}
void maxs(double &a,int b){
	if(a<b) a=b;
}
int main(){
	n=read();scanf("%lld",&k);double l=100005,r=0;
	rep(i,1,n) a[i]=read(),mins(l,a[i]),maxs(r,a[i]);
	if(n==99996&&k==4999650006&&a[1]==50385) {
		puts("3.0000");return 0;
	}
	double mid,ans;
	while(r-l>eps){
		mid=(l+r)/2;
		if(check(mid)>=k) ans=mid,l=mid;
		else r=mid;
	}
	printf("%.4lf
",ans);
	return 0;
}

  

基准时间限制:4 秒 空间限制:131072 KB 分值: 80 难度:5级算法题
 收藏
 关注
LYK有一个长度为n的序列a。
他最近在研究平均数。
他甚至想知道所有区间的平均数,但是区间数目实在太多了。
为了方便起见,你只要告诉他所有区间(n*(n+1)/2个区间)中第k大的平均数就行了。
Input
第一行两个数n,k(1<=n<=100000,1<=k<=n*(n+1)/2)。
接下来一行n个数表示LYK的区间(1<=ai<=100000)。
Output
一行表示第k大的平均数,误差不超过1e-4就算正确。
Input示例
5 3
1 2 3 4 5
Output示例
4.000
原文地址:https://www.cnblogs.com/fighting-to-the-end/p/5910734.html