BZOJ 3210. 花神的浇花集会

传送门

首先按着固定套路,把切比雪夫距离转成曼哈顿距离:$(x,y)=(frac {x+y} {2} , frac {x-y} {2})$

当然代码实现时先不要除以 $2$ ,不然小数比较难受,最后统一除 $2$ 即可

然后可以用前缀和快速计算每个位置作为答案时的贡献

发现 $x$ 和 $y$ 可以单独考虑,所以分开枚举,这样复杂度就很 $ok$

然后写完发现样例都过不了....

分析一波发现,如果把转化后的坐标重新转回来,就有可能变成小数...

这就很有意思了,让我们回到原坐标系考虑一下

考虑对于 $x+y$ 相同的位置,并且 $x,y$ 均为整数那么 $x+1$ 就 $y-1$ ,所以对于 $x+y$ 相同的位置,$x-y$ 每次隔一个数

所以 $x+y$ 为偶数时 $x-y$ 必须为偶数,$x+y$ 为奇数时 $x-y$ 必须为奇数

所以我们只要分别处理一下 $x+y$ 为奇数时的最大值和为偶数时的最大值即可

注意转化后的坐标系内,我们的 $x,y$ 取值是在 $[-1e5,2e5]$

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
const int N=2e5+7;
const ll INF=1e18;
int n,x[N],y[N],bx[N],by[N];
ll sx[N],sy[N],ans[2]={INF,INF},Ans=INF;
int main()
{
    n=read(); int a,b;
    for(int i=1;i<=n;i++)
    {
        a=read(),b=read();
        bx[i]=x[i]=a+b,by[i]=y[i]=a-b;
    }
    sort(bx+1,bx+n+1); sort(by+1,by+n+1);
    for(int i=1;i<=n;i++) sx[i]=sx[i-1]+bx[i];
    for(int i=1;i<=n;i++) sy[i]=sy[i-1]+by[i];
    for(int i=-100000;i<=200000;i+=2)
    {
        ll res=0; int p=lower_bound(bx+1,bx+n+1,i)-bx-1;
        res+=1ll*p*i-sx[p]; res+=sx[n]-sx[p]-1ll*(n-p)*i;
        ans[0]=min(ans[0],res);
    }
    for(int i=-99999;i<=199999;i+=2)
    {
        ll res=0; int p=lower_bound(bx+1,bx+n+1,i)-bx-1;
        res+=1ll*p*i-sx[p]; res+=sx[n]-sx[p]-1ll*(n-p)*i;
        ans[1]=min(ans[1],res);
    }
    for(int i=-100000;i<=200000;i++)
    {
        ll res=0; int p=lower_bound(by+1,by+n+1,i)-by-1;
        res+=1ll*p*i-sy[p]; res+=sy[n]-sy[p]-1ll*(n-p)*i;
        Ans=min(Ans,res+ans[(i%2+2)%2]);
    }
    printf("%lld
",Ans/2);
    return 0;
}
原文地址:https://www.cnblogs.com/LLTYYC/p/11518681.html