2018-2019 ICPC (NWERC 2018) A题 Access Points 构造单调

2018-2019 ICPC NWERC 2018 A题 Access Points 构造单调


传送门: https://codeforces.com/gym/102483/problem/A

题意

给 出 n 个 点 的 a ( x i , y i ) , 然 后 在 二 维 平 面 中 构 造 n 个 点 , 构 造 的 点 可 以 重 合 。 给出n个点的a(x_i,y_i),然后在二维平面中构造n个点,构造的点可以重合。 naxi,yin
构 造 点 的 要 求 为 : 若 为 第 i 和 第 j 个 点 , ( i < j ) , 则 ( x i < = x j , y i < = y j ) \red{构造点的要求为:若为第i和第j个点,(i<j),则(x_i<=x_j,y_i<=y_j)} iji<j(xi<=xjyi<=yj)
贡 献 为 ∑ i = 1 n ∣ p i − a i ∣ 2 , 求 最 小 贡 献 。 贡献为\sum_{i=1}^n|p_i-a_i|^2,求最小贡献。 i=1npiai2

思路

先 将 题 面 转 化 一 下 为 : ∑ i = 1 n ( p i x − a i x ) 2 + ( p i y − a i y ) 2 先将题面转化一下为:\sum_{i=1}^n(p_{ix}-a_{i_x})^2+(p_{iy}-a_{i_y})^2 :i=1n(pixaix)2+(piyaiy)2

看 到 x 和 y 是 相 互 独 立 的 , 所 以 只 需 要 写 出 一 个 函 数 , 然 后 在 套 一 个 即 可 。 看到x和y是相互独立的,所以只需要写出一个函数,然后在套一个即可。 xy

根 据 题 意 , 我 们 构 造 的 p 在 [ 1 , n ] 上 要 是 单 调 递 增 的 。 根据题意,我们构造的p在[1,n]上要是单调递增的。 p[1,n]
那 么 怎 么 求 最 小 的 ∑ i = 1 n ( p i x − a i x ) 2 ? 那么怎么求最小的\sum_{i=1}^n(p_{ix}-a_{ix})^2? i=1n(pixaix)2

分 析 以 下 几 种 情 况 : 分析以下几种情况:

  • a 是 单 调 递 增 的 , 那 根 本 不 用 想 , 让 p i x = a i x , 答 案 为 0. a是单调递增的,那根本不用想,让p_{ix}=a_{ix},答案为0. apix=aix0.
  • a 全 为 一 个 数 , 那 p 也 为 a 的 平 均 值 , 答 案 也 为 0. a全为一个数,那p也为a的平均值,答案也为0. apa0.
  • a 是 不 递 增 的 , 这 是 本 题 的 关 键 , 因 为 p 是 递 增 的 , 如 果 a 越 来 越 小 , 而 p 越 来 越 大 , 那 该 怎 么 构 造 呢 ? a是不递增的,这是本题的关键,因为p是递增的,如果a越来越小,而p越来越大,那该怎么构造呢? apap

当a是单调递增的时候,非常好构造所以我们不让a有递减的部分,也就是把任意形式的a都转化为单调递增。

我们对于a中一段的串,取一个平均值,再处理下一个串,使当前串的平均值要大于上一个串的平均值,我们要做到将一段长度的平均值递增即可。

问 题 : 怎 么 维 护 一 段 长 度 平 均 值 递 增 ? 问题:怎么维护一段长度平均值递增?

回 答 : 暴 力 O ( n 2 ) ? N o , 单 调 栈 即 可 。 回答:暴力O(n^2)?\red{No},单调栈即可。 O(n2)No

我 们 用 单 调 栈 维 护 一 段 串 的 平 均 值 递 增 即 可 , 因 为 x 和 y 独 立 , 所 以 y 也 是 如 此 。 我们用单调栈维护一段串的平均值递增即可,因为x和y独立,所以y也是如此。 xyy

Code(62MS)

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef pair<int, int> pdd;

#define INF 0x3f3f3f3f
#define lowbit(x) x & (-x)
#define mem(a, b) memset(a , b , sizeof(a))
#define FOR(i, x, n) for(int i = x;i <= n; i++)

// const ll mod = 998244353;
// const ll mod = 1e9 + 7;
// const double eps = 1e-6;
// const double PI = acos(-1);
// const double R = 0.57721566490153286060651209;

const int N = 1e6 + 10;
ll x[N], y[N];
int n;

double sum(ll *A, int n) {
    stack<pair<ll, int> > s;
    double ans = 0;
    for(int i = 1;i <= n; i++) {
        ll a = A[i]; int l = 1;
        while(!s.empty() && s.top().first * l >= s.top().second * a) { // 使栈内平均值递增
            l += s.top().second;
            a += s.top().first;
            s.pop();
        }
        s.push({a, l});
    }
    int i = n;
    while(!s.empty()) {
        double tmp = 1.0 * s.top().first / s.top().second;
        int l = s.top().second;
        s.pop();
        for(int j = 0;j < l; j++) {
            ans += (tmp - A[i - j]) * (tmp - A[i - j]);
        }
        i -= l;
    }
    return ans;
}

void solve() {
    scanf("%d",&n);
    for(int i = 1;i <= n; i++) {
        scanf("%lld%lld",&x[i], &y[i]);
    }

    printf("%lf\n" ,sum(x, n) + sum(y, n));
}


int main() {
	solve();
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值