[POI2006]MAG-Warehouse 题解
通过这篇 常用距离算法详解,我们可以将 切比雪夫距离 转换为 曼哈顿距离。
为了防止掉精度,我们需要将原坐标系中的点 \((x,y)\) 转化为 \((x+y,x-y)\) 而不是 \((\frac{x+y}{2} , \frac{x-y}{2})\)。
然后可以将两个维度分开来算。此处以 \(x\) 为例
假设我们选出的坐标为 \(x\)。
我们假设把每个坐标拆成 \(t_i\) 个点。
将所有 \(x_i\) 排序。
我们要使 \(\sum_{i=1}^{n} | x-x_i |\) 最小。
根据初一的知识,我们可以得出 \(x=x_{\lfloor \frac n2 \rfloor}\)。
当然,根据数据范围,拆点行不通,所以可以先求出 \(t\) 的前缀和再二分查找。
根据上述过程,我们可以得出在曼哈顿距离的坐标下的答案 \((x_{ans},y_{ans})\)。
但是注意到我们在之前的处理中并没有除以二,所以的出来的可能不是整点。
此处运用了 oscar 大佬的方法,直接暴力判断点就好了。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
#define int long long
#define rep(i,a,b) for(register int i=a;i<=b;++i)
#define Rep(i,a,b) for(register int i=a;i>=b;--i)
inline int read()
{
bool f=0;int x=0;char ch;
do{ch=getchar();f|=(ch=='-');}while(!isdigit(ch));
do{x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}while(isdigit(ch));
return f?-x:x;
}
inline void write(int x)
{
if(x<0)x=-x,putchar('-');
if(x>9)write(x/10);putchar(x%10+'0');
}
inline void writesp(int x)
{
write(x);putchar(' ');
}
inline void writeln(int x)
{
write(x);puts("");
}
struct node1
{
int x;
int t;
bool operator <(const node1 &b)const
{
return x<b.x;
}
}x[maxn];
struct node2
{
int y;
int t;
bool operator <(const node2 &b)const
{
return y<b.y;
}
}y[maxn];
int qx[maxn],qy[maxn],qz[maxn];
int n;
int sumx[maxn],sumy[maxn];
int check(int xx,int yy)
{
int ans=0;
rep(i,1,n)
{
ans+=max(abs(xx-qx[i]),abs(yy-qy[i]))*qz[i];
}
return ans;
}
signed main()
{
n=read();
rep(i,1,n)
{
int a=read(),b=read();
x[i].x=a+b;y[i].y=a-b;
qz[i]=x[i].t=y[i].t=read();
qx[i]=a;qy[i]=b;
}
sort(x+1,x+1+n);
sort(y+1,y+1+n);
rep(i,1,n)sumx[i]=sumx[i-1]+x[i].t;
rep(i,1,n)sumy[i]=sumy[i-1]+y[i].t;
int tempx=sumx[n],tempy=sumy[n];
rep(i,1,n)sumx[i]<<=1;
rep(i,1,n)sumy[i]<<=1;
int posx=lower_bound(sumx+1,sumx+1+n,tempx)-sumx;
int posy=lower_bound(sumy+1,sumy+1+n,tempy)-sumy;
int sx=x[posx].x,sy=y[posy].y;
int nx=((sx+sy)/2),ny=((sx-sy)/2);
int ans1=check(nx,ny),ans2=check(nx+1,ny),ans3=check(nx,ny+1),ans4=check(nx+1,ny+1);
if(ans4<=ans3&&ans4<=ans2&&ans4<=ans1) printf("%d %d\n",nx+1,ny+1);
else if(ans3<=ans4&&ans3<=ans2&&ans3<=ans1)printf("%d %d\n",nx,ny+1);
else if(ans2<=ans4&&ans2<=ans3&&ans2<=ans1)printf("%d %d\n",nx+1,ny);
else if(ans1<=ans2&&ans1<=ans3&&ans1<=ans4)printf("%d %d\n",nx,ny);
return 0;
}
我好菜啊。——ฅ(OωO)ฅ