P1404 平均数
题目描述
给一个长度为n的数列,我们需要找出该数列的一个子串,使得子串平均数最大化,并且子串长度>=m。
输入格式
N+1行,
第一行两个整数n和m
接下来n行,每行一个整数a[i],表示序列第i个数字
输出格式
一个整数,他是最大平均数的1000倍,如果末尾有小数,直接舍去,不要用四舍五入求整。
输入输出样例
输入 #1
10 6 6 4 2 10 3 8 5 9 4 1
输出 #1
6500
说明/提示
【数据范围】
60% M<=N<=10000
100% M<=N<=100000 0<=a[i]<=2000
思路
先求部分和S(x),然后连续子序列平均值就转化为S-x平面上的斜率:ave(x,y)=(S(y)-s(x-1))/(y-x+1)。考虑x<y<z的三个点如果S(y)是上凸的,则这个点一定没贡献。所以有用的点构成一个下凸的折线,用一个队列维护这个折线,加入新点时(如当前点为i,则新点为i-m),如果与队尾2个点形成上凸,则删除队尾点。如果队首2个点与当前点形成上凸,同理删除队首点。最后每次队首元素都是与点i斜率最大的点,再求最值就行了
代码:
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=100010;
double ans;
int q[N],t,h;
int n,m,a[N];
double k(int x,int y) {
return (a[y]-a[x]+0.0)/(y-x);
}
int main () {
scanf("%d%d",&n,&m);
for(int i=1,x; i<=n; i++) {
scanf("%d",&x);
a[i]=a[i-1]+x;
}
for(int i=m; i<=n; i++) {
while(t-h>=2&&k(i-m,q[t-1])<k(i-m,q[t-2]))
t--;
q[t++]=i-m;
while(t-h>=2&&k(i,q[h])<k(i,q[h+1]))
h++;
ans=max(ans,k(i,q[h]));
}
printf("%d\n",(int)floor(ans*1000));
return 0;
}

浙公网安备 33010602011771号