好久好久没有更新博客了,现在开始要好好学了。
分数规划第一题吧,第一次听说这个东西是在冬令营,现在算是做过一道题了吧。
二分最后的答案,之后把原数组每个数都减去这个答案,如果这个解成立的话,必须有一段区间和为正数,这样的话,我们把它转化为前缀和,只要找一个 sum[j]>=sum[i] 就好了。
但是,这道题有一个问题,就是答案要求是分数,这样我们只能求出一个小数。我们就要在判断的时候记录一下,最后输出的时候再化简就好了。
#include<bits/stdc++.h>
#define N 100000
using namespace std;
long long n,k,ansl,ansr,q,p,t;
long long a[N+5];
double l,r,mid;
double sum[N+5];
inline char nc()
{
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline long long read()
{
long long x=0,b=1;
char c=nc();
for(;!(c<='9'&&c>='0');c=nc())if(c=='-')b=-1;
for(;c<='9'&&c>='0';c=nc())x=x*10+c-'0';
return x*b;
}
inline bool judge(double x)
{
for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i]*1.0-x;
int pos=0;
for(int i=k;i<=n;i++)
{
if(sum[i]>=sum[pos])
{
ansl=pos+1,ansr=i;
return true;
}
if(sum[i-k+1]<sum[pos])pos=i-k+1;
}
return false;
}
inline long long gcd(long long a,long long b)
{
return b==0?a:gcd(b,a%b);
}
int main()
{
freopen("in.txt","r",stdin);
n=read(),k=read();
for(int i=1;i<=n;i++)a[i]=read();
l=r=a[1];
for(int i=2;i<=n;i++)l=min(l,a[i]*1.0),r=max(r,a[i]*1.0);
for(int i=1;i<=50;i++)
{
mid=(l+r)/2.0;
if(judge(mid))l=mid;
else r=mid;
}
q=ansr-ansl+1;
for(int i=ansl;i<=ansr;i++)p+=a[i];
t=gcd(abs(p),q);
printf("%lld/%lld",p/t,q/t);
return 0;
}