大致题意: 给定一个圆环,你可以选择连续(Lsim R)个数(个数必须为偶数),求最大的平均值。
分数规划
这种平均值的问题一看就是分数规划。
考虑我们二分一个答案(x),设我们选择的数是(a_{1sim t})则需要满足:
[frac{sum_{i=1}^ta_i}tge xLeftrightarrowsum_{i=1}^t(a_i-x)ge 0
]
也就是说,给所有数减去(x)之后,就是要求是否存在一个长度为偶数且在(L sim R)范围内的区间使得这段区间内数的总和大于等于(0)。
单调队列
感觉没什么好说的吧。
单调队列维护前缀和的最小值即可。
唯一要注意的就是因为长度必须是偶数,要开两个单调队列。
关于答案
我们发现,二分出的答案是小数,而题目要求分数。
实际上,我们只要记录下得出答案时的长度,然后以答案乘长度为分子,长度为分母,约分一下就可以了。
代码
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 200000
#define DB long double
#define eps 1e-8
using namespace std;
int n,k,Mn,Mx,a[N+5],q[2][N+5];DB s[N+5];
I long long gcd(Con long long& x,Con long long& y) {return y?gcd(y,x%y):x;}
I bool Check(Con DB& x)//验证答案
{
RI i,op,H[2]={1,1},T[2]={0,0};
for(i=1;i^Mn;++i) s[i]=s[i-1]+a[i]-x;for(;i<=n;++i)//计算前部分的前缀和
{
op=i&1,H[op]<=T[op]&&q[op][H[op]]==i-Mx&&++H[op];//弹出不合法元素
W(H[op]<=T[op]&&s[q[op][T[op]]]>=s[i-Mn]) --T[op];q[op][++T[op]]=i-Mn;//加入新元素
if((s[i]=s[i-1]+a[i]-x)-s[q[op][H[op]]]>=-eps) return k=i-q[op][H[op]],1;//如果符合条件直接return 1
}return 0;
}
int main()
{
RI i;scanf("%d%d%d",&n,&Mn,&Mx),Mn&1&&++Mn,Mx&1&&--Mx;
for(i=1;i<=n;++i) scanf("%d",a+i),a[n+i]=a[i];n<<=1;//圆环,所以复制一遍
DB l=0,r=1e9,mid;W(r-l>eps) Check(mid=(l+r)/2)?l=mid:r=mid;//分数规划
Check(l);long long s=l*k+0.5,g=gcd(s,k);
return g^k?printf("%lld/%d",s/g,k/g):printf("%d",s/g),0;//输出分数
}