[HDU2993]MAX Average Problem

题面描述

传送门

思路

状态转移方程

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})

决策单调性

设有 j < k i m j<k\le 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})

如果

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}

均对答案有贡献,那么

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}

( 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)

对于未来状态 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}

仍对答案有贡献,

证明

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}

( 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)

s u m k = s u m i + v a l , t j > t k sum_k=sum_i+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)

仅需证明 v a l ( t j ) v a l ( t k ) val*(t-j)\ge val*(t-k)

由于 v a l > 0 val>0

则成立。

因此 k k 永远优于 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}

因此,根据上文

c a l c ( k , i ) c a l c ( j , i ) calc(k,i)\ge calc(j,i) 时, k k 优于 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) 时, q h e a d + 1 q_{head+1} 优于 q h e a d q_{head}

因此观出, c a l c ( q h e a d , i ) calc(q_{head},i) h e a d 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})

即可。

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; 
}

猜你喜欢

转载自blog.csdn.net/zyszlb2003/article/details/94427222