题目大意:给定一个环,要求在这个环上截取长度为偶数且在[L,R]区间内的一段,要求平均值最大
看到环果断倍增
看到平均值最大果断二分答案
看到长度[L,R]果断单调队列
对数组维护一个前缀和,对前缀和维护单调递增的单调队列
每扫过一个数sum[i],将sum[i-L]加入单调队列,再把距离i超过R的点删掉
长度为偶数?对奇数位置和偶数位置分别维护一个单调队列即可
每次找到大于0的子串之后记录一下分母再退出就行了
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 100100
#define EPS 1e-7
using namespace std;
int n,L,R,max_num,a[M<<1];
long double sum[M<<1];
long long numerator,denominator;
int q[2][M],r[2],h[2];
bool Judge(long double x)
{
int i;
for(i=1;i<=n;i++)
sum[i]=sum[i-1]+(a[i]-x);
r[0]=r[1]=h[0]=h[1]=0;
for(i=L;i<=n;i++)
{
int *q=::q[i&1],&r=::r[i&1],&h=::h[i&1],x=i-L;
while( r-h>=1 && sum[q[r]]>sum[x] )
q[r--]=0;
q[++r]=x;
while( i-q[h+1]>R )
q[++h]=0;
if(sum[i]-sum[q[h+1]]>=0)
return denominator=i-q[h+1];
}
return false;
}
long double Bisecion()
{
long double l=0,r=max_num;
while(r-l>EPS)
{
long double mid=(l+r)/2;
if( Judge(mid) )
l=mid;
else
r=mid;
}
return (l+r)/2;
}
int main()
{
int i;
cin>>n>>L>>R;
if(L&1) L++;
if(R&1) R--;
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
max_num=max(max_num,a[i]);
a[i+n]=a[i];
}
n<<=1;
long double ans=Bisecion();
numerator=(long long)(ans*denominator+0.5);
long long gcd=__gcd(numerator,denominator);
numerator/=gcd;
denominator/=gcd;
if(denominator==1)
cout<<numerator<<endl;
else
cout<<numerator<<'/'<<denominator<<endl;
return 0;
}