BZOJ5090: [Lydsy1711月赛]组题(01分数规划)

5090: [Lydsy1711月赛]组题

Time Limit: 1 Sec  Memory Limit: 256 MB
Submit: 785  Solved: 186
[Submit][Status][Discuss]

Description

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

Input

第一行包含两个整数n,k(1<=n<=100000,1<=k<=n),分别表示题目的总量和题数的下界。
第二行包含n个整数a_1,a_2,...,a_n(|a_i|<=10^8),分别表示每道题目的难度系数。

Output

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

Sample Input

5 3
1 4 -2 -3 6

Sample Output

5/4

HINT

Source

思路:01分数规划,二分平均值,然后就是求最大的连续的长度不小于K的值,然后由于是需要输出分子分母形式,我们在二分的同时记录“和”与“长度”,最后约分输出即可。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
using namespace std;
const int maxn=100010;
int a[maxn],N,K; double b[maxn]; ll A,B,sum[maxn];
bool check(double Mid)
{
    rep(i,1,N) b[i]=b[i-1]+a[i]-Mid; int pos=0;
    rep(i,K,N) {
        if(b[i]-b[pos]>=0){
            A=sum[i]-sum[pos];
            B=i-pos; return true;
        }
        if(b[i-K+1]<b[pos]) pos=i-K+1;
    }return false;
}
int main()
{
    scanf("%d%d",&N,&K);
    double L=-100000000,R=100000000,Mid; int num=40;
    rep(i,1,N) scanf("%d",&a[i]),;
    rep(i,1,N) sum[i]=sum[i-1]+a[i];
    while(num--){
        Mid=(L+R)/2;
        if(check(Mid)) L=Mid;
        else R=Mid;
    }
    if(A<0) putchar('-'),A=abs(A);
    ll g=__gcd(A,B);
    printf("%lld/%lld
",A/g,B/g);
    return 0;
}

但是不知道为什么我自己的check函数是WA的,难道是delta一直做加减法引起的精度问题?

bool check(double Mid)
{
    rep(i,1,N) b[i]=(double)a[i]-Mid; int head=1; double delta=0;
    rep(i,1,N) {
        delta+=b[i];
        while(i-head+1>K&&b[head]<0) delta-=b[head++];
        if(i-head+1>=K&&delta>=0){
            A=sum[i]-sum[head-1]; B=i-head+1;
            return true;
        }
    }return false;
}
原文地址:https://www.cnblogs.com/hua-dong/p/9973520.html