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 最大
這是一個比較顯然的分數規劃問題,我們二分答案然後求長度至少爲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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章