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使得 最大
這是一個比較顯然的分數規劃問題,我們二分答案然後求長度至少爲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;
}