凸包——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
输入:
5
1 1 4 5 3
输出:
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
代码:
#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;
}
原文地址:https://blog.csdn.net/qq_73702550/article/details/140306835
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!