http://acm.hdu.edu.cn/showproblem.php?pid=2993
题意:给你一段长度为n的数列, 求其长度不小于 K 的平均值最大的子串。
解析参考:http://blog.ac521.org/?p=565
大意是先将问题转化为求斜率的问题,然后将朴素的N^2的算法用下凸曲线维护(要推导一些性质),降为2N的复杂度
数形结合
#include <cstdio>
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
int N,K;
int sum[100010];
struct point
{
double x,y;
};
void read(int & a)
{
char ch;
while (ch = getchar(),ch < '0' || ch > '9');
a = ch - '0';
while (ch = getchar(),ch >= '0' && ch <= '9')
a = a*10 + ch - '0';
}
double solve()
{
double maxx = 0;
static point s[100010];
int head = 1,tail = 0;
for (int j = K; j <= N; j++)
{
int k = j - K;
while (tail-1 >= head && (s[tail].x - s[tail-1].x)*(sum[k] - s[tail].y) - (s[tail].y - s[tail-1].y)*(k - s[tail].x)<0)//if (tail-1 >= head)
{
tail --;
}
s[++tail].x = k;
s[tail].y = sum[k];
while (head+1 <= tail && (sum[j] - s[head].y)/(j - s[head].x) < (sum[j] - s[head+1].y)/(j - s[head+1].x))
head++;
double temp = (double)(sum[j] - s[head].y)/(j - s[head].x);
//cout<<temp<<endl;
if (temp > maxx) maxx = temp;
}
return maxx;
}
int main()
{
freopen("test.txt","r",stdin);
while(~scanf("%d%d",&N,&K))
{
sum[0] = 0;
for (int i = 1; i <= N; i++)
{
read(sum[i]);
sum[i] += sum[i-1];
}
printf("%.2lf\n",solve());
}
return 0;
}