1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 using namespace std; 7 typedef long long int64; 8 const double eps=1e-5; 9 const int maxn=100005; 10 int n,a[maxn],sum[maxn],pos[maxn]; 11 double l,r,mid,ans,b[maxn],s[maxn],list[maxn]; 12 int64 k; 13 int lowbit(int x){return x&(-x);} 14 void insert(int x){for (int i=x;i<=n+1;i+=lowbit(i)) sum[i]++;} 15 int64 query(int x){ 16 int64 temp=0; 17 for (int i=x;i;i-=lowbit(i)) temp+=sum[i]; 18 return temp; 19 } 20 bool judge(double num){ 21 memset(sum,0,sizeof(sum)); b[0]=0; 22 for (int i=1;i<=n;i++) b[i]=a[i]-num; 23 for (int i=1;i<=n;i++) s[i]=s[i-1]+b[i],list[i]=s[i]; 24 list[n+1]=0; sort(list+1,list+n+2); 25 for (int i=1;i<=n;i++) pos[i]=lower_bound(list+1,list+n+2,s[i])-list; 26 pos[0]=lower_bound(list+1,list+n+2,0)-list; 27 int64 tot=0; 28 insert(pos[0]); 29 for (int i=1;i<=n;i++) tot+=query(pos[i]),insert(pos[i]); 30 return tot>=k; 31 } 32 int main(){ 33 scanf("%d%lld",&n,&k); 34 for (int i=1;i<=n;i++) scanf("%d",&a[i]); 35 l=1.0,r=100000.0; 36 while (l+eps<r){ 37 mid=(l+r)/2.0; 38 if (judge(mid)) l=mid; 39 else r=mid; 40 } 41 printf("%.4lf ",l); 42 return 0; 43 }
题目大意:
LYK有一个长度为n的序列a。
他最近在研究平均数。
他甚至想知道所有区间的平均数,但是区间数目实在太多了。
为了方便起见,你只要告诉他所有区间(n*(n+1)/2个区间)中第k大的平均数就行了。
做法:二分很容易理解,问题转化为有多少个区间的平均数>=x,对于平均数,我们把每个数减去x,若该区间的sum大于等于0,则说明该区间的平均数大于等于x,那么问题便进一步的转化为有多少个区间的和非负,这个可以在nlogn的时间内求出,求出前缀和并离散化后,用线段树或树状数组可以求出来,时间总复杂度为nlognlogR,可以过,这是我的运行情况:Accepted 1500 ms 5592 KB 。