51nod1711 平均数

本文介绍了一种通过二分查找解决区间平均数问题的方法。针对大量区间平均数的计算需求,利用预处理和二维偏序处理技巧,有效地找到了第k大的平均数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

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

题解

首先看到这种平均数我们很套路的想到二分
我们先看一下在什么时候(i,j)有贡献,设当前二分值为mid
sum[j]sum[i]ji>mid时(i,j)的平均数就比mid大,此时有贡献
那么我们可以移一下项,得:sum[i]midi<sum[j]midj
那么我们预处理这个东西然后搞一下二维偏序就好了
注意0也要加进去

贴代码

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#define db double
#define ll long long
using namespace std;
const int maxn=10005,md=100000007;
struct node{
    db x,y,z;
}a[maxn],b[maxn];
int i,j;
ll p,ans,c,ge,nt,k,n;
ll cc[maxn];
int cmp(node x,node y){
    return x.z<y.z;
}
bool check(node x,node y){
    return x.x*y.y>x.y*y.x;
}
int main(){
    freopen("forgive.in","r",stdin);
    freopen("forgive.out","w",stdout);
    scanf("%d%d",&n,&p);
    for (i=1;i<=n;i++) scanf("%lf%lf",&a[i].x,&a[i].y);
    cc[0]=1;
    c=(p*p)%md;
    for (i=1;i<=n;i++) cc[i]=(cc[i-1]*(1-p+md))% md;
    ans=3*(n*p+cc[n])-3;
    ans=ans%md;
    nt=n-1;
    for (i=1;i<=n;i++){
        for (j=1;j<=n;j++){
            b[j].x=a[j].x-a[i].x;
            b[j].y=a[j].y-a[i].y;
            b[j].z=atan2(b[j].y,b[j].x);
            if (i==j) b[i].z=21474844;
        }
        sort(b+1,b+n+1,cmp);
        k=1;
        ge=0;
        for (j=1;j<=nt;j++){
            while (check(b[j],b[k%nt+1])) {
                ge++;
                k=k%nt+1;
            }
            ans=(ans-(cc[n-ge-2]*c)%md+md)% md;
            if (ge) ge--; else k=k%nt+1;
        }
    }
    printf("%d",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值