/** 鼠标样式 **/

Shu-How Zの小窝

Loading...

凸包——G - Highest Ratio

G - Highest Ratio

来源:AtCoder Beginner Contest 341-G

题目描述:

给定长度为 \(N\) 的序列 \(A = (A_1, A_2, \ldots, A_N)\)

对于每个 \(k = 1, 2, \ldots, N\),解决以下问题:

选择整数 \(r\),使得序列 \(A\) 的第 \(k\) 到第 \(r\) 项的平均值最大化,并满足 \(k \leq r \leq N\)

这里,序列 \(A\) 的第 \(k\) 到第 \(r\) 项的平均值定义为:

\(\frac{1}{r - k + 1} \sum_{i=k}^{r} A_i\)

约束条件:

  • \(1 \leq N \leq 2 \times 10^5\)
  • \(1 \leq A_i \leq 10^6\)
  • 所有输入值都是整数。

Output:

输出格式:

  • 打印 \(N\) 行。
  • \(i\) 行(\(1 \leq i \leq N\))应包含当 \(k = i\) 时问题的答案。
  • 您的输出将被视为正确,如果对于每一行,打印值与真实值之间的绝对或相对误差最多为 \(10^{-6}\)

Sample

输入:

5
1 1 4 5 3

输出:

2.80000000
3.33333333
4.50000000
5.00000000
3.00000000

思路:

\(Si\) 为前 i 个元素的前缀和,在平面上放N个点\((i, Si)\),第 x 个点到第 y 个点连线的斜率即为区间\((x + 1, y)\)的平均值(平均值 = \((Sy - Sx) / (y - x)\) = 斜率),在这个图上求凸包即可

在求凸包的循环中,如果栈顶的点不属于凸包,则弹出栈顶元素,该点的ans即为该点与弹出后的栈顶点的斜率值。
求完凸包后,凸包上的相邻两点的斜率即为ans

代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=3e5+10;
int T;
vector<int> stk;

// 定义点的结构体
struct Point{
  double x, y;
  // 重载减法运算符,用于计算向量差
  Point operator-(Point& p){
    Point t;
    t.x = x - p.x;
    t.y = y - p.y;
    return t;
  }
  // 计算向量叉积
  double cross(Point p) {
    return x * p.y - p.x * y;
  }
};

// 比较函数,用于排序点
bool cmp(Point& p1, Point& p2) {
  if (p1.x != p2.x) return p1.x < p2.x;
  return p1.y < p2.y;
}

Point point[N];  // 保存无序的点
int convex[N];  // 保存组成凸包的点的下标
int n;  // 无序点的个数
int sum[N];  // 前缀和数组
double ans[N];  // 保存每个点的最大斜率
bool st[N];  // 标记点是否在凸包中(未在代码中使用)

// 计算两点间的斜率
double kk(Point& a, Point& b) {
  return (b.y - a.y) * 1.00 / (b.x - a.x);
}

// 构建凸包
void GetConvexHull() {
  int total = 0;
  convex[total++] = n;  // 将最后一个点(索引为 n)加入凸包
  ans[n] = 1.00 * (sum[n] - sum[n - 1]);  // 计算最后一个点的斜率
  for (int i = n - 1; i >= 0; i--) {
    while (total > 1 && (point[convex[total - 1]] - point[convex[total - 2]]).cross(point[i] - point[convex[total - 1]]) <= 0) {
      ans[convex[total - 1]] = kk(point[convex[total - 1]], point[convex[total - 2]]);  // 计算斜率
      total--;  // 弹出栈顶点
    }
    convex[total++] = i;  // 将当前点加入凸包
  }
  for (int i = total - 1; i >= 1; i--) {
    ans[convex[i]] = kk(point[convex[i]], point[convex[i - 1]]);  // 计算斜率
  }
  return;
}

// 解决问题的主函数
void solve() {
  cin >> n;  // 读取点的个数
  int x;
  sum[0] = 0;
  point[0] = {0, 0};
  for (int i = 1; i <= n; i++) {
    cin >> x;
    sum[i] = sum[i - 1] + x;  // 计算前缀和
    point[i] = {i, sum[i]};  // 初始化点
  }
  GetConvexHull();  // 构建凸包
  for (int i = 0; i < n; i++) {
    printf("%.8lf\n", ans[i]);  // 输出每个点的最大斜率
  }
}

signed main() {
  solve();  // 调用解决问题的主函数
  return 0;
}
posted @ 2024-09-26 09:36  Violet_fan  阅读(4)  评论(0编辑  收藏  举报