题面描述
思路
状态转移方程
F i = max ( F j , s u m i − s u m j i − j ) F_i=\max(F_j,\frac{sum_i-sum_j}{i-j}) Fi=max(Fj,i−jsumi−sumj)
决策单调性
设有 j < k ≤ i − m j<k\le i-m j<k≤i−m
max ( F k , s u m i − s u m k i − k ) ≥ max ( F j , s u m i − s u m j i − j ) \max(F_k,\frac{sum_i-sum_k}{i-k})\ge \max(F_j,\frac{sum_i-sum_j}{i-j}) max(Fk,i−ksumi−sumk)≥max(Fj,i−jsumi−sumj)
如果
s u m i − s u m k i − k , s u m i − s u m j i − j \frac{sum_i-sum_k}{i-k},\frac{sum_i-sum_j}{i-j} i−ksumi−sumk,i−jsumi−sumj
均对答案有贡献,那么
s u m i − s u m k i − k ≥ s u m i − s u m j i − j \frac{sum_i-sum_k}{i-k}\ge \frac{sum_i-sum_j}{i-j} i−ksumi−sumk≥i−jsumi−sumj
则
( s u m i − s u m k ) ∗ ( i − j ) ≥ ( s u m i − s u m j ) ∗ ( i − k ) (sum_i-sum_k)*(i-j)\ge(sum_i-sum_j)*(i-k) (sumi−sumk)∗(i−j)≥(sumi−sumj)∗(i−k)
对于未来状态 t t t,若
s u m t − s u m k t − k , s u m t − s u m j t − j \frac{sum_t-sum_k}{t-k},\frac{sum_t-sum_j}{t-j} t−ksumt−sumk,t−jsumt−sumj
仍对答案有贡献,
证明
s u m t − s u m k t − k ≥ s u m t − s u m j t − j \frac{sum_t-sum_k}{t-k}\ge\frac{sum_t-sum_j}{t-j} t−ksumt−sumk≥t−jsumt−sumj
( s u m t − s u m k ) ∗ ( t − j ) ≥ ( s u m t − s u m j ) ∗ ( t − k ) (sum_t-sum_k)*(t-j)\ge(sum_t-sum_j)*(t-k) (sumt−sumk)∗(t−j)≥(sumt−sumj)∗(t−k)
由 s u m k = s u m i + v a l , t − j > t − k sum_k=sum_i+val,t-j>t-k sumk=sumi+val,t−j>t−k
( s u m i − s u m k ) ∗ ( t − j ) ≥ ( s u m i − s u m j ) ∗ ( t − k ) (sum_i-sum_k)*(t-j)\ge (sum_i-sum_j)*(t-k) (sumi−sumk)∗(t−j)≥(sumi−sumj)∗(t−k)
仅需证明 v a l ∗ ( t − j ) ≥ v a l ∗ ( t − k ) val*(t-j)\ge val*(t-k) val∗(t−j)≥val∗(t−k)
由于 v a l > 0 val>0 val>0
则成立。
因此 k k k永远优于 j j j
踢队头
c a l c ( k , i ) = s u m i − s u m k i − k ≥ c a l c ( j , i ) = s u m i − s u m j i − j calc(k,i)=\frac{sum_i-sum_k}{i-k}\ge calc(j,i)=\frac{sum_i-sum_j}{i-j} calc(k,i)=i−ksumi−sumk≥calc(j,i)=i−jsumi−sumj
因此,根据上文
当 c a l c ( k , i ) ≥ c a l c ( j , i ) calc(k,i)\ge calc(j,i) calc(k,i)≥calc(j,i)时, k k k优于 j j j
当 c a l c ( q h e a d + 1 , i ) ≥ c a l c ( q h e a d , i ) calc(q_{head+1},i)\ge calc(q_{head},i) calc(qhead+1,i)≥calc(qhead,i)时, q h e a d + 1 q_{head+1} qhead+1优于 q h e a d q_{head} qhead
因此观出, c a l c ( q h e a d , i ) calc(q_{head},i) calc(qhead,i)随 h e a d head head增大而减小,维护一个上凸壳。
踢队尾
c a l c ( i − m , q t a i l − 1 ) ≤ c a l c ( q t a i l , q t a i l − 1 ) calc(i-m,q_{tail-1})\le calc(q_{tail},q_{tail-1}) calc(i−m,qtail−1)≤calc(qtail,qtail−1)
即可。
AC code
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int N=1e5+10;
const int size=1<<20;
inline char gc()
{
static char buf[size],*p1,*p2;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,size,stdin),p1==p2)?EOF:*p1++;
}
#define gc gc()
inline void qr(int &x)
{
x=0;int f=1;char c=gc;if(c==EOF)return;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc;}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=gc;}x*=f;
}
int s[N];int q[N],l,r;int n,m;
inline double calc(int j,int i)
{
return (double)(s[i]-s[j])/(i-j);
}
int main()
{
while(qr(n),n)
{
qr(m);
s[0]=0;
for(int i=1;i<=n;i++)qr(s[i]),s[i]+=s[i-1];
l=1;r=0;q[1]=0;double ans=0;
for(int i=m;i<=n;i++)
{
while(l<r&&calc(q[r],q[r-1])>=calc(i-m,q[r-1]))--r;
q[++r]=i-m;
while(l<r&&calc(q[l+1],i)>=calc(q[l],i))++l;
ans=max(ans,calc(q[l],i));
}
printf("%.2lf\n",ans);
}
return 0;
}