分析
题目大意:给出 (n) 个点的坐标 ((x_i, y_i)) ,其中 (iin [1,n]) ,要求构造相应的点 ((p_i,q_i)) ,(p,q) 满足 (p_{i-1}leq p_{i},~q_{i-1}leq q_{i}),使得 (sum ((x_i-p_i)^2+(y_i-q_i)^2)) 最小。
注意到 (x,y) 和 (p,q) 都是分别独立的,因此只需求 (sum (x_i-p_i)^2) 最小值即可。
先给出具体做法:对于每个 (x_k) ,都创建一个有值和 (sum) (简记为 (s)),(cnt) (简记为 (c))两个属性的结点,当当前结点 (cur) 与先前结点满足: (s_{cur}/c_{cur} < s_{last}/c_{last}) 时,就将 (cur) 与 (last) 进行合并得到更新后的 (cur) ,如此下去直到最后的 (cur) 与 (last) 满足: (s_{cur}/c_{cur} geq s_{last}/c_{last})
其中合并方法为: 将 (s_{cur}) 加上 (s_{last}) , (c_{cur}) 加上 (c_{last}) ,删去 (last) 。
下面说明这样做即可得到最优解:
简便起见,分别将 (cur,last) 结点记为 (e_{i+1},e_i) ,(forall i) ,(e_i) 有属性 (s_i,c_i) ,(s_i/c_i) 记为 (v_i) 。
设 (e_i) 对应的区间为 ([L,k]) ,(e_{i+1}) 对应的区间为 ([k+1,R]) 。
先给出引理:对于 (frac{sum_{i=1}^n (a_i-x)^2}{n}) ,当且仅当 (x=overline a) 时取到最小值。
证明:展开,可知 (frac{sum_{i=1}^n (a_i-x)^2}{n}) 是关于 (x) 的二次函数,由展开式可知,其在且只在 (x=overline a) 取到最小值。
- 当 (v_{i+1} geq v_i) 时,只需证明不合并比合并的花费小即可。
记 (v=(s_i+s_{i+1})/(c_i+c_{i+1}))
由所给的做法,对于相应的 (p值) 可知在 ([L,k]) ,(p=v_i) ,而在 ([k+1,R]) ,(p=v_{i+1}) ,这样的 (p) 值是合法的。
只需证明 (sum_{j=L}^R (x_j-v)^2 geq sum_{u=L}^k(x_u-v_i)^2+sum_{w=k+1}^R (x_w-v_{i+1})^2)
由引理,
(sum_{u=L}^k(x_u-v)^2geq sum_{u=L}^k(x_u-v_i)^2)
(sum_{w=k+1}^R (x_w-v)^2 geq sum_{w=k+1}^R (x_w-v_{i+1})^2)
将上两式相加即证。
- 当 (v_{i+1} < v_i) 时,只需证明合并比不合并的花费小即可。
由所给的做法,对于相应的 (p值) ,记在 ([L,k]) ,(p=p_f) ,而在 ([k+1,R]) ,(p=p_s) ,应有 (p_sgeq p_f) 。
只需证明 (sum_{j=L}^R (x_j-v)^2 leq sum_{u=L}^k(x_u-p_f)^2+sum_{w=k+1}^R (x_w-p_s)^2)
因为 (sum_{w=k+1}^R (x_w-p_s)^2 geq sum_{u=L}^k(x_u-p_f)^2)
故 (sum_{u=L}^k(x_u-p_f)^2+sum_{w=k+1}^R (x_w-p_s)^2 geq sum_{u=L}^k(x_u-p_f)^2+sum_{w=k+1}^R (x_w-p_f)^2 = sum_{j=L}^R (x_j-p_f)^2)
由引理,显然有 (sum_{j=L}^R (x_j-p_f)^2 geq sum_{j=L}^R (x_j-v)^2)
至此证毕。
所以对于所给的做法,每一次操作都是最优的做法,因此整个做法是最优的。
代码:
#pragma GCC optimize("O3")
#include<bits/stdc++.h>
using namespace std;
#define endl '
'
#define debug(x) cerr << #x << ": " << x << endl
#define pb(a) push_back(a)
#define set0(a) memset(a,0,sizeof(a))
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dwn(i,a,b) for(int i=(a);i>=(b);i--)
#define ceil(a,b) (a+(b-1))/b
#define INF 0x3f3f3f3f
#define ll_INF 0x7f7f7f7f7f7f7f7f
typedef long long ll;
typedef pair<int,int> PII;
typedef pair<double,double> PDD;
inline int read()
{
int x=0,y=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') y=-1;c=getchar();}
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*y;
}
const int N=1e5+5;
const double eps=1e-12;
int n;
double x[N], y[N];
double stk_sum[N];
int stk_cnt[N];
int top;
double cal(double a[]){
set0(stk_sum), set0(stk_cnt);
top=0;
rep(i, 1, n){
double cur_sum=a[i]; int cur_cnt=1;
while(top && cur_sum*stk_cnt[top]+eps<stk_sum[top]*cur_cnt){
cur_sum+=stk_sum[top];
cur_cnt+=stk_cnt[top--];
}
stk_sum[++top]=cur_sum, stk_cnt[top]=cur_cnt;
}
int id=0;
double res=0;
rep(i, 1, top) rep(j, 1, stk_cnt[i]){
id++;
double avg=stk_sum[i]/stk_cnt[i];
res+=(avg-a[id])*(avg-a[id]);
}
return res;
}
int main(){
cin>>n;
rep(i, 1, n) cin>>x[i]>>y[i];
double res=cal(x)+cal(y);
printf("%.10lf
", res);
return 0;
}