bzoj5090 [Lydsy1711月赛]组题 二分

Description


著名出题人小Q的备忘录上共有n道可以出的题目,按照顺序依次编号为1到n,其中第i道题目的难度系数被小Q估计
为a_i,难度系数越高,题目越难,负数表示这道题目非常简单。小Q现在要出一套难题,他决定从备忘录中选取编
号连续的若干道题目,使得平均难度系数最高。当然,小Q不能做得太过分,一套题目必须至少包含k道题目,因此
他不能通过直接选取难度系数最高的那道题目来组成一套题。请写一个程序,帮助小Q挑选平均难度系数最高的题
目。

n,k(1<=n<=100000,1<=k<=n)
(|a_i|<=10^8)

输出一个既约分数p/q或-p/q,即平均难度系数的最大值。

Solution


考虑前缀和,那么问题变成求一对l和r使得 s[r]s[l]rl s [ r ] − s [ l ] r − l 最大
这是一个比较显然的分数规划问题,我们二分答案然后求长度至少为k的最大子段和即可

注意输出的时候负号的位置

Code


#include <stdio.h>
#include <string.h>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)

typedef long long LL;
const double eps=0.000001;
const int N=200005;

double b[N];
LL s[N],a[N],up,down;
int n,m;

bool check(double mid) {
    rep(i,1,n) b[i]=b[i-1]+a[i]-mid;
    double min=0; int pos=0;
    rep(i,m,n) {
        if (b[i]-min>0) {
            up=s[i]-s[pos];
            down=i-pos;
            return true;
        }
        if (b[i-m+1]<min) min=b[i-m+1],pos=i-m+1;
    }
    return false;
}

LL gcd(LL x,LL y) {
    return !y?x:gcd(y,x%y);
}

int main(void) {
    scanf("%d%d",&n,&m);
    rep(i,1,n) scanf("%lld",&a[i]);
    rep(i,1,n) s[i]=s[i-1]+a[i];
    for (double l=-1e8,r=1e8;r-l>eps;) {
        double mid=(l+r)*0.5;
        if (check(mid)) l=mid;
        else r=mid;
    }
    LL GCD=gcd(up,down);
    if (GCD<0) GCD=-GCD;
    printf("%lld/%lld\n", up/GCD,down/GCD);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值