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个点,构造的点可以重合。
给出n个点的a(xi,yi),然后在二维平面中构造n个点,构造的点可以重合。
构
造
点
的
要
求
为
:
若
为
第
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)}
构造点的要求为:若为第i和第j个点,(i<j),则(xi<=xj,yi<=yj)
贡
献
为
∑
i
=
1
n
∣
p
i
−
a
i
∣
2
,
求
最
小
贡
献
。
贡献为\sum_{i=1}^n|p_i-a_i|^2,求最小贡献。
贡献为∑i=1n∣pi−ai∣2,求最小贡献。
思路
先 将 题 面 转 化 一 下 为 : ∑ 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(pix−aix)2+(piy−aiy)2
看 到 x 和 y 是 相 互 独 立 的 , 所 以 只 需 要 写 出 一 个 函 数 , 然 后 在 套 一 个 即 可 。 看到x和y是相互独立的,所以只需要写出一个函数,然后在套一个即可。 看到x和y是相互独立的,所以只需要写出一个函数,然后在套一个即可。
根
据
题
意
,
我
们
构
造
的
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(pix−aix)2?
分 析 以 下 几 种 情 况 : 分析以下几种情况: 分析以下几种情况:
- a 是 单 调 递 增 的 , 那 根 本 不 用 想 , 让 p i x = a i x , 答 案 为 0. a是单调递增的,那根本不用想,让p_{ix}=a_{ix},答案为0. a是单调递增的,那根本不用想,让pix=aix,答案为0.
- a 全 为 一 个 数 , 那 p 也 为 a 的 平 均 值 , 答 案 也 为 0. a全为一个数,那p也为a的平均值,答案也为0. a全为一个数,那p也为a的平均值,答案也为0.
- a 是 不 递 增 的 , 这 是 本 题 的 关 键 , 因 为 p 是 递 增 的 , 如 果 a 越 来 越 小 , 而 p 越 来 越 大 , 那 该 怎 么 构 造 呢 ? a是不递增的,这是本题的关键,因为p是递增的,如果a越来越小,而p越来越大,那该怎么构造呢? a是不递增的,这是本题的关键,因为p是递增的,如果a越来越小,而p越来越大,那该怎么构造呢?
当a是单调递增的时候,非常好构造所以我们不让a有递减的部分,也就是把任意形式的a都转化为单调递增。
我们对于a中一段的串,取一个平均值,再处理下一个串,使当前串的平均值要大于上一个串的平均值,我们要做到将一段长度的平均值递增即可。
问 题 : 怎 么 维 护 一 段 长 度 平 均 值 递 增 ? 问题:怎么维护一段长度平均值递增? 问题:怎么维护一段长度平均值递增?
回 答 : 暴 力 O ( n 2 ) ? N o , 单 调 栈 即 可 。 回答:暴力O(n^2)?\red{No},单调栈即可。 回答:暴力O(n2)?No,单调栈即可。
我 们 用 单 调 栈 维 护 一 段 串 的 平 均 值 递 增 即 可 , 因 为 x 和 y 独 立 , 所 以 y 也 是 如 此 。 我们用单调栈维护一段串的平均值递增即可,因为x和y独立,所以y也是如此。 我们用单调栈维护一段串的平均值递增即可,因为x和y独立,所以y也是如此。
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();
}