http://acm.csu.edu.cn:20080/csuoj/problemset/problem?pid=2323
思路:首先明确一点,行和列可以分开计算,没有影响。先考虑把所有企鹅移动到同一行的情况,因为棋盘的长宽和企鹅数量相等,且同一个格子只能有一个企鹅,所以这些企鹅应该各自独占一列,为了让步数尽量小,把横坐标排序后,第
i
i
i只企鹅应该移动到横坐标为
i
i
i的位置,对应的贡献为
a
b
s
(
x
i
−
i
)
abs(x_i-i)
abs(xi−i);接下来考虑把它们移动到同一行的问题,结论是把纵坐标从小到大排序,取得中位数
y
[
m
i
d
]
y[mid]
y[mid],把所有企鹅移动到这个位置是最优的。可以用反证法证明,不妨设移动到的纵坐标为
a
a
a,当
a
<
y
[
m
i
d
]
a<y[mid]
a<y[mid]时,我们可以令所有企鹅向
y
[
m
i
d
]
y[mid]
y[mid]逼近,这样下侧的企鹅需要移动的次数加1,上侧的企鹅需要移动的次数减1,由中位数的性质可知下侧企鹅的数量小于上侧企鹅的数量,故
a
a
a不是最优解,当
a
>
y
[
m
i
d
]
a>y[mid]
a>y[mid]时也有此结论,所以最优解是取中位数。如果
n
n
n是偶数的时候,中位数怎么确定呢?我们不妨设
n
=
2
k
n=2k
n=2k,此时取
a
k
a_k
ak或者
a
k
+
1
a_{k+1}
ak+1都可以,答案是一样的,数学证明如下:
若
取
a
k
,
则
a
n
s
1
=
∑
i
=
1
k
a
k
−
a
i
+
∑
i
=
k
+
1
2
k
a
i
−
a
k
=
∑
i
=
k
+
1
2
k
a
i
−
∑
i
=
1
k
a
i
若取a_k,则ans_1=\sum_{i=1}^{k}a_k-a_i+\sum_{i=k+1}^{2k}a_i-a_k=\sum_{i=k+1}^{2k}a_i-\sum_{i=1}^{k}a_i
若取ak,则ans1=i=1∑kak−ai+i=k+1∑2kai−ak=i=k+1∑2kai−i=1∑kai
若
取
a
k
+
1
,
则
a
n
s
2
=
∑
i
=
1
k
+
1
a
k
+
1
−
a
i
+
∑
i
=
k
+
2
2
k
a
i
−
a
k
+
1
=
∑
i
=
k
+
2
2
k
a
i
−
∑
i
=
1
k
+
1
a
i
+
2
∗
a
k
+
1
=
∑
i
=
k
+
1
2
k
a
i
−
∑
i
=
1
k
a
i
若取a_{k+1},则ans_2=\sum_{i=1}^{k+1}a_{k+1}-a_i+\sum_{i=k+2}^{2k}a_i-a_{k+1}=\sum_{i=k+2}^{2k}a_i-\sum_{i=1}^{k+1}a_i+2*a_{k+1}=\sum_{i=k+1}^{2k}a_i-\sum_{i=1}^{k}a_i
若取ak+1,则ans2=i=1∑k+1ak+1−ai+i=k+2∑2kai−ak+1=i=k+2∑2kai−i=1∑k+1ai+2∗ak+1=i=k+1∑2kai−i=1∑kai
那么分别计算两种情况的值,取最小的即可。
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=6e5+5;
int n,x[maxn],y[maxn];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d %d",&x[i],&y[i]);
sort(x+1,x+1+n);
sort(y+1,y+1+n);
ll ct1=0,ct2=0,ct3=0,ct4=0;
int mid=x[(n+1)>>1];
for(int i=1;i<=n;i++)
ct1+=(ll)abs(x[i]-mid),ct2+=(ll)abs(x[i]-i);
mid=y[(n+1)>>1];
for(int i=1;i<=n;i++)
ct3+=(ll)abs(y[i]-mid),ct4+=(ll)abs(y[i]-i);
printf("%lld\n",min(ct1+ct4,ct2+ct3));
return 0;
}