您的位置:首页 > 其它

HDU MAX Average Problem(斜率优化DP)

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

前提条件:

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肯定会慢的。

代码如下:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
const int MAXN = 100010;
double sum[MAXN];
int que[MAXN];
int front, tail;

double get_k(int i, int j) {
return (sum[i] - sum[j]) / (i - j);
}

int main() {
int n, k;
while (scanf("%d%d", &n, &k) == 2) {
int temp;
sum[0] = 0;
for (int i = 1; i <= n; i++) {
scanf("%d", &temp);
sum[i] = sum[i - 1] + temp;
}
front = 0, tail = -1;
double ans = 0;
for (int i = k; i <= n; i++) {
int now = i - k;
while (front < tail && get_k(que[tail], que[tail - 1]) > get_k(que[tail], now)) tail--;
que[++tail] = now;
while (front < tail && get_k(que[front], que[front + 1]) < get_k(que[front + 1], i)) front++;
ans = max(ans, get_k(que[front], i));
}
printf("%.2lf\n", ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: