DJ的企鹅

题目描述

继在鹅厂工作的DJ训练完鹅厂的企鹅们之后,DJ发明了一个新游戏。该游戏在n*n的棋盘上进行,其中恰好有n个企鹅,企鹅向四个方向之一移动一格算作一步。DJ希望用最少的总步数把这些企鹅变成一排,即所有企鹅都在同一行或同一列(由于DJ目不斜视,他认为所有企鹅在同一对角线上的情况不算一列)。 企鹅们为了避免DJ的毒打需要尽快排成一排,你能帮可怜的小企鹅们解决这个问题吗。注意任意时刻不能有两个企鹅在同一格。

输入

第一行一个整数n(n<=6*10^5)表明棋盘大小。 接下来n行,每行两个整数Xi,Yi(1<=Xi,Yi<=n),表示第i只企鹅的坐标。保证初始 企鹅的坐标互不相同。

输出

一行一个整数表示最少需要的步数。

样例输入

5

1 2

2 4

3 4

5 1

5 3

样例输出

6

思路

中位数性质!最优的就是移动到左右尽可能相等的位置

左边a个企鹅,右边b个企鹅,移动到x=c的位置,当a>b时,c往左移动更优,因为c左边的企鹅都少走一步,c右边的企鹅多走一步,因为a>b所以总步数更少......

AC代码

#include <iostream>
#include <stdio.h>
#include <queue>
#include <set>
#include <string>
#include <map>
#include <cmath>
#include <algorithm>
#include <cstring>
#define ll long long
using namespace std;
const int maxn = 6e5 + 5;
const int inf = 0x3f3f3f3f;
int x[maxn], y[maxn];
ll numx[maxn], numy[maxn];
ll sumx[maxn], sumy[maxn];
int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i)
        scanf("%d %d", &x[i], &y[i]);
    sort(x + 1, x + n + 1);
    sort(y + 1, y + n + 1);
    ll now = 1;
    for (int i = 1; i <= n; ++i)
    {
        sumx[i] = sumx[i - 1];
        numx[i] = numx[i - 1];
        while (x[now] == i)
        {
            sumx[i] += i;
            ++numx[i];
            ++now;
        }
    }
    now = 1;
    for (int i = 1; i <= n; ++i)
    {
        sumy[i] = sumy[i - 1];
        numy[i] = numy[i - 1];
        while (y[now] == i)
        {
            sumy[i] += i;
            ++numy[i];
            ++now;
        }
    }
 
    ll pjx = 1, pjy = 1;
    for (int i = 1; i <= n; ++i)
        if (numx[i] > numx[n] / 2)
        {
            pjx = i;
            break;
        }
    for (int i = 1; i <= n; ++i)
        if (numy[i] > numy[n] / 2)
        {
            pjy = i;
            break;
        }
    ll ansx1 = 0, ansy1 = 0, ansx = 0, ansy = 0;
    ansy = numy[pjy - 1] * pjy - sumy[pjy - 1];
    ansy += (sumy[n] - sumy[pjy]) - (numy[n] - numy[pjy]) * pjy;
    ansx = numx[pjx - 1] * pjx - sumx[pjx - 1];
    ansx += (sumx[n] - sumx[pjx]) - (numx[n] - numx[pjx]) * pjx;
    for (int i = 1; i <= n; ++i) //转移需要的步数
    {
        ansx1 += abs(i - x[i]);
        ansy1 += abs(i - y[i]);
    }
    ll ans = min(ansx1 + ansy, ansy1 + ansx);
    printf("%lld\n", ans);
    return 0;
}
发布了145 篇原创文章 · 获赞 30 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_43984169/article/details/102545664
DJ
今日推荐