CSUOJ 2323 疯狂的企鹅II 贪心 思维

114 篇文章 0 订阅
48 篇文章 1 订阅

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(xii);接下来考虑把它们移动到同一行的问题,结论是把纵坐标从小到大排序,取得中位数 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 akans1=i=1kakai+i=k+12kaiak=i=k+12kaii=1kai
若 取 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+1ans2=i=1k+1ak+1ai+i=k+22kaiak+1=i=k+22kaii=1k+1ai+2ak+1=i=k+12kaii=1kai
那么分别计算两种情况的值,取最小的即可。

#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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值