凸包——G - Highest Ratio

G - Highest Ratio

来源:AtCoder Beginner Contest 341-G

题目描述:

给定长度为 N N N 的序列 A = ( A 1 , A 2 , ... , A N ) A = (A_1, A_2, \ldots, A_N) A=(A1,A2,...,AN)。

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

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

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

1 r − k + 1 ∑ i = k r A i \frac{1}{r - k + 1} \sum_{i=k}^{r} A_i r−k+11∑i=krAi

约束条件:

  • 1 ≤ N ≤ 2 × 1 0 5 1 \leq N \leq 2 \times 10^5 1≤N≤2×105
  • 1 ≤ A i ≤ 1 0 6 1 \leq A_i \leq 10^6 1≤Ai≤106
  • 所有输入值都是整数。

Output:

输出格式:

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

Sample

输入:

cpp 复制代码
5
1 1 4 5 3

输出:

cpp 复制代码
2.80000000
3.33333333
4.50000000
5.00000000
3.00000000

思路:

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

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

求完凸包后,凸包上的相邻两点的斜率即为ans

代码:

cpp 复制代码
#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;
}
相关推荐
马剑威(威哥爱编程)33 分钟前
除了递归算法,要如何优化实现文件搜索功能
java·开发语言·算法·递归算法·威哥爱编程·memoization
算法萌新——11 小时前
洛谷P2240——贪心算法
算法·贪心算法
湖北二师的咸鱼1 小时前
专题:二叉树递归遍历
算法·深度优先
重生之我要进大厂1 小时前
LeetCode 876
java·开发语言·数据结构·算法·leetcode
KBDYD10102 小时前
C语言--结构体变量和数组的定义、初始化、赋值
c语言·开发语言·数据结构·算法
Crossoads2 小时前
【数据结构】排序算法---桶排序
c语言·开发语言·数据结构·算法·排序算法
自身就是太阳2 小时前
2024蓝桥杯省B好题分析
算法·职场和发展·蓝桥杯
孙小二写代码3 小时前
[leetcode刷题]面试经典150题之1合并两个有序数组(简单)
算法·leetcode·面试
little redcap3 小时前
第十九次CCF计算机软件能力认证-1246(过64%的代码-个人题解)
算法
David猪大卫3 小时前
数据结构修炼——顺序表和链表的区别与联系
c语言·数据结构·学习·算法·leetcode·链表·蓝桥杯