[题解] [洛谷P1404] 平均数
洛谷P1404 平均数
题目描述#
给一个长度为
输入格式#
第一行两个整数
接下来
输出格式#
一个整数,表示最大平均数的
数据规模#
对于
对于
题解#
朴素的思想是枚举所有的子串,找到最大平均数,时间复杂度
考虑优化,本题的特殊限制条件是子串长度不得小于
考虑扩展子串,如果向后扩展的同时向前扩展,则向后扩展的子串会和后续子串向前扩展的子串重合,形成枚举的重复,故只向前或向后扩展。此处采用向前扩展。优化的关键是在
考虑二分答案。对于一个选定的基准数作为平均数的情况考虑扩展,易得以下扩展策略:
- 前缀的平均数小于基准数,舍弃前缀;
- 前缀的平均数大于等于基准数,则保留前缀。
因此,只需要在枚举长度为
AC代码#
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define int long long
using namespace std;
const int MAXN = 1e6 + 3;
int n, m;
double a[MAXN];
double sum = 0.0; //维护只取m个数的和
bool check(double x) {
sum = 0.0;
for (int i = 1; i <= m; i++) {
sum += a[i];
}
double ans = 0.0;
double preSum = 0.0; //维护往前延伸的最大平均数的和(分子)
double preNum = 0.0; //维护往前延伸的最大平均数的数量(分母)
for (int i = 1; i <= n - m + 1; i++) { //从m开始枚举子串的第一个数的位置
double preAvg = 0.0; //往前延伸的最大平均数
if (preNum != 0) preAvg = preSum / preNum;
if (preAvg < x) preSum = a[i - 1], preNum = 1.0; //之前的平均数达不到x,则只保留新出现的数
else preSum += a[i - 1], preNum += 1.0; //否则在保留之前的前缀的基础上加上新出现的数
ans = max(ans, max((sum + preSum) / ((double)m + preNum), sum / (double)m)); //更新答案
sum -= a[i]; //减去子串的第一个数
sum += a[i + m]; //加上新出现的一个数
}
return ans >= x;
}
signed main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
double l = 0, r = 2000, mid;
while (l + 1e-5 < r) {
mid = (l + r) / 2.0;
if (check (mid)) l = mid;
else r = mid;
}
cout << (int)(r * 1000.0) << '\n';
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 2分钟学会 DeepSeek API,竟然比官方更好用!
· .NET 使用 DeepSeek R1 开发智能 AI 客户端
· DeepSeek本地性能调优
· autohue.js:让你的图片和背景融为一体,绝了!
· 10亿数据,如何做迁移?