题意:给一个长度为 n 的序列,找出长度 >= k 的平均值最大的连续子序列。
思路:
1,用一个单调队列来维护解集。
2,假设队列中从头到尾已经有元素a b c。那么当d要入队的时候,我们维护队列的上凸性质,即如果g[d,c]<g[c,b],那么就将c点删除。直到找到g[d,x]>=g[x,y]为止,并将d点加入在该位置中。
3,求解时候,从队头开始,如果已有元素a bc,当i点要求解时,如果g[b,a]<sum[i],那么说明b点比a点更优,a点可以排除,于是a出队。最后dp[i]=getDp(q[head])。
参考博客:http://blog.csdn.net/dgq8211/article/details/12443049
http://www.cnblogs.com/jackge/archive/2013/04/17/3026219.html
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn=100010; double sum[maxn]; int q[maxn]; double cross(int i,int j,int k){ double tmp; tmp=(k-i)*(sum[j]-sum[i])-(j-i)*(sum[k]-sum[i]); return tmp; } double max(double a,double b){ return a>b?a:b; } int Input(){ char c; int ans; while(c=getchar(),c<'0' || c>'9') ; ans=c-'0'; while(c=getchar(),c>='0' && c<='9') ans=ans*10+c-'0'; return ans; } double f(int i,int k){ i=q[i]; return (sum[k]-sum[i])/(k-i); } int main(){ //freopen("input.txt","r",stdin); int n,k; while(~scanf("%d%d",&n,&k)){ sum[0]=0; int i,j; for(i=1;i<=n;i++) sum[i]=sum[i-1]+Input(); int head=0,rear=0; double ans=0; for(i=k;i<=n;i++){ j=i-k; while(head<rear && cross(q[rear-1],q[rear],j)>=0) rear--; q[++rear]=j; while(head<rear && f(head+1,i)>=f(head,i)) head++; ans=max(ans,f(head,i)); } printf("%.2lf\n",ans); } return 0; }