HDU 2993 MAX Average Problem (斜率DP)

MAX Average Problem

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4416    Accepted Submission(s): 1106

Problem Description
Consider a simple sequence which only contains positive integers as a1, a2 ... an, and a number k. Define ave(i,j) as the average value of the sub sequence ai ... aj, i<=j. Let’s calculate max(ave(i,j)), 1<=i<=j-k+1<=n.
 
Input
There multiple test cases in the input, each test case contains two lines. The first line has two integers, N and k (k<=N<=10^5). The second line has N integers, a1, a2 ... an. All numbers are ranged in [1, 2000].
 
Output
For every test case, output one single line contains a real number, which is mentioned in the description, accurate to 0.01.
 
Sample Input
10 6
6 4 2 10 3 8 5 9 4 1
 
Sample Output
6.50
 
Source
 
Recommend
chenrui
 
 
 
 

这个也是论文上的例题,给你一个正数序列,注意全是正数,否则就不满足和的单调性了,关于这个结论某些部分就不能在运用了,我先说一下前提条件,我就是前提条件没搞请,才弄的模模糊糊的,弄清楚前提条件后就会发现其实不是很难的。

前提条件:

1.所有的数均是(保证了他们的和是单调递增的)

2.求的是连续的序列,且序列的长度大于等于k

3.求的是序列的最大平均值,也就是(i, sum[i])值中斜率最大的那个值

解体思路:

现在我只是干讲,如果感觉不形象的话,可以参考那篇著名的论文。

由于我们是要求斜率最大值,如果枚举的话,我们肯定是把当前的点与它前面的所有的点求斜率,取最大值。

现在我们想降低复杂度,我们可以从两个方面入手,

1,去掉每个位置前面的那些在后来的枚举中不可能产生最优解的点

2,快速的去定位最优解

首先讲第一个:

1.如何减少不必要的枚举呢?

我们假设存在三个点,i,j, k三个点构成的是上凸包,现在我们沿着j,k作延长线,如何后来的点在延长线的下方,那么该后来的点是不能构成最优解的,因为当前延长线的解已经比后来的点构成的所有的点优或则说与i构成的直线的斜率一定比与j构成的斜率大,如果后来的点在延长线的上方,那么你会发现与k构成的斜率肯定比与j构成的斜率大,那么问题就出现了,j不可能在后来的更新中形成最优解,那么就可以将其删除,这样在后来的枚举中少了它了。很神奇的证明,不过的确特别的有用。

2.如何更快的去定位最优解呢?

一般的做法就是二分,不过这里的做法很绝,把原来O(NlgN)的做法优化到了,O(N)

还是把不可能构成最优解的删掉,(注意sum[i]是单调递增的),如果当前构不成最优解,那么在后来的点着中是不可能构成最优解的,因此可以删掉,到底为什么,还是自己看自己想。这里维持最小长度为k还是很巧秒的,不过HDU交C++可过,交G++TLE,据说只要有C++那么它的服务器系统肯定是windows,那么交G++调用MingW肯定会慢的。

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 
 5 using namespace std;
 6 
 7 const int maxn=100010;
 8 
 9 double sum[maxn];
10 int q[maxn];
11 
12 double cross(int i,int j,int k){
13     double tmp;
14     tmp=(k-i)*(sum[j]-sum[i])-(j-i)*(sum[k]-sum[i]);
15     return tmp;
16 }
17 
18 double max(double a,double b){
19     return a>b?a:b;
20 }
21 
22 int Input(){
23     char c;
24     int ans;
25     while(c=getchar(),c<'0' || c>'9') ;
26     ans=c-'0';
27     while(c=getchar(),c>='0' && c<='9')
28         ans=ans*10+c-'0';
29     return ans;
30 }
31 
32 double f(int i,int k){
33     i=q[i];
34     return (sum[k]-sum[i])/(k-i);
35 }
36 
37 int main(){
38 
39     //freopen("input.txt","r",stdin);
40 
41     int n,k;
42     while(~scanf("%d%d",&n,&k)){
43         sum[0]=0;
44         int i,j;
45         for(i=1;i<=n;i++)
46             sum[i]=sum[i-1]+Input();
47         int head=0,rear=0;
48         double ans=0;
49         for(i=k;i<=n;i++){
50             j=i-k;
51             while(head<rear && cross(q[rear-1],q[rear],j)>=0)
52                 rear--;
53             q[++rear]=j;
54             while(head<rear && f(head+1,i)>=f(head,i))
55                 head++;
56             ans=max(ans,f(head,i));
57         }
58         printf("%.2lf\n",ans);
59     }
60     return 0;
61 }
原文地址:https://www.cnblogs.com/jackge/p/3026219.html