bzoj 1696 贪心

本文探讨了在存在多头牛的情况下,如何通过数学方法找到最优的吃草位置,以确保每头牛都能获得最大面积的草地。文章详细介绍了算法步骤,包括针对奇数和偶数数量的牛进行优化策略,最终计算出最小总距离和可行点的数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/*

其实sum和min都可以拆开的

即

求min( sum{|x-xi|} + sum{|y-yi|} )

那么思路很清晰了,,,

对于奇数。只有一个中位数,那么我们找1~n所有x的中位数和y的中位数,,这个就是它的点。。但是要注意,这个点不能和牛重合。如果重合,那么就取牛的上下左右四个点,即“没有两头牛的吃草位置是相邻的”,可以证明这是最优。。

对于偶数。有2个中位数,,那么我们就要找这两个中位数中所有的可行点。(其实这个范围内所有的点都是可行点,即答案有(xx-x+1)*(yy-y+1)个。。但是注意,这里面不能有牛,所以每找到一个牛,就要减去一个答案。
*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
#define rep(i, n) for(int i=0; i<(n); ++i)
#define for1(i,a,n) for(int i=(a);i<=(n);++i)
#define for2(i,a,n) for(int i=(a);i<(n);++i)
#define for3(i,a,n) for(int i=(a);i>=(n);--i)
#define for4(i,a,n) for(int i=(a);i>(n);--i)
#define CC(i,a) memset(i,a,sizeof(i))
#define read(a) a=getint()
#define print(a) printf("%d", a)
#define dbg(x) cout << #x << " = " << x << endl
#define printarr(a, n, m) rep(aaa, n) { rep(bbb, m) cout << a[aaa][bbb]; cout << endl; }
inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }
inline const int max(const int &a, const int &b) { return a>b?a:b; }
inline const int min(const int &a, const int &b) { return a<b?a:b; }

const int N=10005;
struct dat { int x, y; }a[N];
bool cmpx(const dat &a, const dat &b) { return a.x<b.x; }
bool cmpy(const dat &a, const dat &b) { return a.y<b.y; }
int n, ans1, ans2;
bool check(int x, int y) {
    for1(i, 1, n) if(a[i].x==x && a[i].y==y) return 0;
    return 1;
}
int main() {
    read(n);
    for1(i, 1, n) read(a[i].x), read(a[i].y);
    if(n&1) {
        int x, y;
        sort(a+1, a+1+n, cmpx); x=a[(n>>1)+1].x;
        sort(a+1, a+1+n, cmpy); y=a[(n>>1)+1].y;
        if(check(x, y)) {
            for1(i, 1, n) ans1+=abs(x-a[i].x)+abs(y-a[i].y);
            ans2=1;
        }
        else {
            static int tp[4];
            CC(tp, 0);
            int fx[]={x+1, x-1, x, x}, fy[]={y, y, y-1, y+1}; ans1=~0u>>1;
            for1(i, 1, n) rep(j, 4) tp[j]+=abs(fx[j]-a[i].x)+abs(fy[j]-a[i].y);
            rep(j, 4) if(ans1>tp[j]) ans1=tp[j], ans2=1; else if(ans1==tp[j]) ++ans2;
        }
    }
    else {
        int x, y, xx, yy;
        sort(a+1, a+1+n, cmpx); x=a[(n>>1)].x; xx=a[(n>>1)+1].x;
        sort(a+1, a+1+n, cmpy); y=a[(n>>1)].y; yy=a[(n>>1)+1].y;
        ans2=(xx-x+1)*(yy-y+1);
        for1(i, 1, n) {
            if(a[i].x>=x && a[i].x<=xx && a[i].y>=y && a[i].y<=yy) --ans2;
            ans1+=abs(x-a[i].x)+abs(y-a[i].y);
        }
    }
    printf("%d %d", ans1, ans2);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值