【bzoj 十连测】[noip2016十连测第三场]Problem A: 平均数(二分答案+归并排序求逆序对)

59 篇文章 0 订阅
15 篇文章 0 订阅

Problem A: [noip2016十连测第三场]平均数

Time Limit: 10 Sec   Memory Limit: 256 MB
Submit: 165   Solved: 51
[ Submit][ Status][ Web Board]

Description

有一天,小A得到了一个长度为n的序列。他把这个序列的所有连续子序列都列了出来,并对每一个子序列都求了其
平均值,然后他把这些平均值写在纸上,并对它们进行排序,最后他报出了第k小的平均值。你要做的就是模仿他
的过程。

Input

第一行两个整数n,k,意义如题中所述。
第二行n个正整数,即为小A得到的序列。

Output

一行一个实数,表示第k小的平均值,保留到小数点后4位。
【 数据范围与约定】
对于 40%的数据, n≤1000
对于 100%的数据, n≤100000, k≤n*(n+1)/2, 序列中的数≤10^9

Sample Input

6 10
3 5 4 6 1 2

Sample Output

3.6667

HINT

【题解】【二分答案+归并排序求逆序对】
[谁告诉我这是day1 T1!!!!!! 打死它打死它!]
【看看数据范围,呵呵!枚举必然TTT】
【二分答案,二分平均数,每二分到一个答案,就把每个元素都减去当前的平均数,并求前缀和。当前情况下,和小于等于0的区间是满足条件的,求当前有多少个区间满足条件。我们要求的最后答案,是满足有>=k个区间的最小值】
【但是,不能直接枚举区间,会T,因为每个区间[i,j]可以用sum[j]-sum[i-1]求出,所以直接求逆序对数即可】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define esp 1e-6
using namespace std;
ll k,num;
int n,a[100010],maxn;
double ans,sum[100010],tmp[100010];
inline double abss(double x)
{
    if(x>=0) return x;
     else return -x;
}
void qsort(int f,int l)
{
    if(f<l)
     {
        int mid=(f+l)>>1;
        qsort(f,mid); qsort(mid+1,l);
        int i=f,k=f,j=mid+1;
        while(i<=mid&&j<=l)
        if(sum[j]-sum[i]<=esp)
          {
            tmp[k++]=sum[j++];
            num+=(ll)mid-i+1;
          }
         else tmp[k++]=sum[i++];
        while(i<=mid) tmp[k++]=sum[i++];
        while(j<=l) tmp[k++]=sum[j++];
        for(i=f;i<=l;++i) sum[i]=tmp[i];
     }
}
inline bool check(double x)
{
    memset(tmp,0,sizeof(tmp));
    for(int i=1;i<=n;++i) sum[i]=sum[i-1]+(double)(a[i]-x);
    num=0; qsort(1,n);
    for(int i=1;i<=n;++i)
     if(sum[i]<=0) num++;
    return (num>=k);
}
inline void find(double l,double r)
{
    double mid;
    while(!(abss(r-l)<=esp))
     {
        mid=(l+r)/(2.0);
        if(check(mid)) ans=mid,r=mid;
         else l=mid;
     }
}
int main()
{
    //freopen("int.txt","r",stdin);
    //freopen("my.txt","w",stdout);
    int i;
    scanf("%d%lld",&n,&k);
    for(i=1;i<=n;++i) 
     {
        scanf("%d",&a[i]);
        if(maxn<a[i]) maxn=a[i];
     }
    find(0,maxn);
    printf("%.4lf\n",ans);
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值