1. 程式人生 > >BZOJ5090: [Lydsy1711月賽]組題(01分數規劃)

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

claris原創,本oj版權所有,翻版必究

 

思路: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\n",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;
}