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
题解
这题好像Usaco打过的一题啊。。
直接二分答案,由于答案要求最大且答案一定唯一所以说在答案为这个的时候这个串里面一定有一段是>=0的,那么暴力check一下就好
check的时候记录一下前缀和最小值,找到答案后记录一下原前缀和以及长度
这样就可以了。。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const double eps=1e-7;
LL gcd(LL a,LL b)
{
if(a==0)return b;
return gcd(b%a,a);
}
LL a[110000],sum[110000];
int n,k;
double s[110000];
LL tmp,cnt;
bool check(double p)
{
s[0]=0.0;double minn=0.0;int u=0;
for(int i=1;i<=n;i++)s[i]=s[i-1]+1.0*a[i]-p;
for(int i=k;i<=n;i++)
{
if(s[i]-minn>=0)
{
cnt=(LL)(i-u);
tmp=sum[i]-sum[u];
return true;
}
if(s[i-k+1]<minn)minn=s[i-k+1],u=i-k+1;
}
return false;
}
int main()
{
double l=1e8,r=-1e8;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);sum[i]=sum[i-1]+a[i];
l=min(l,1.0*a[i]);
r=max(r,1.0*a[i]);
}
while(l+eps<=r)
{
double mid=(l+r)/2;
if(check(mid))l=mid;
else r=mid;
}
LL sum=gcd(tmp,cnt);
if(sum<0)sum=-sum;
printf("%lld/%lld",tmp/sum,cnt/sum);
return 0;
}