P3964 [TJOI2013]松鼠聚會 切比雪夫距離 轉化 曼哈頓距離
題意:
求\(n\)個點的切比雪夫距離和值的最小值
切比雪夫距離:對於\(x_1,y_1,x_2,y_2\)定義兩個點的切比雪夫距離為\(max(|x_1-x_2|,|y_1-y_2|)\)
範圍&性質:\(1\le n\le 10^5,-10^9\le x,y \le 10^9\)
分析:
首先我們先來了解一個小結論:
列舉到\((0,0)\)點曼哈頓距離為1的點:
\((1,0),(0,1),(-1,0),(0,-1),(0.5,0.5),(0.5,-0.5),(-0.5,-0.5),(-0.5,0.5)\)
列舉到\((0,0)\)點切比雪夫距離為1的點:
\((0,1),(1,1),(-1,1),(-1,-1),(0,-1),(1,-1),(1,0),(-1,0)\)
將上述的點畫在座標系裡可以得到兩個正方形,且第二個是第一個向左旋轉\(45^\circ\)後擴充套件2倍得到
由此我們可以推得
將一個點\((x,y)\)的座標變為\((x+y,x−y)\)後,原座標系中的曼哈頓距離 \(=\)新座標系中的切比雪夫距離
將一個點\((x,y)\)的座標變為\((\frac {x+y}2,\frac {x-y}2)\) 後,原座標系中的切比雪夫距離 \(=\) 新座標系中的曼哈頓距離
由以上結論我們可以將給定點的切比雪夫距離轉化為曼哈頓距離,對於每一個點他的座標變化為了\((gx,gy)\)
由於曼哈頓距離有一個優越的性質:可以快速求多個點到一個點的距離和值,所以我們對於新的點進行排序
記列舉的松鼠為\(k\),那麼:
\[ans= \sum_{i=1}^n dis(i,k)=\sum_{i=1}^n[ \;|gx_i-gx_k| \;+\; |gy_i-gy_k|\; ] \]
化簡得到
\[ans=|gx_1-gx_k|+|gx_2-gx_k| \dots + +|gx_n-gx_k|+|gy_1-gy_k|+|gy_2-gy_k|\dots +|gy_n-gy_k| \]
只要維護一下字首和就可以將複雜度降到單次\(\omicron(1)\)
程式碼:
#include<bits/stdc++.h> using namespace std; namespace zzc { const int maxn = 1e5+5; long long x[maxn],y[maxn],nx[maxn],ny[maxn]; long long sumx[maxn],sumy[maxn]; long long ans,n; long long calc(long long i) { long long tmpx=lower_bound(nx+1,nx+n+1,x[i])-nx; long long tmpy=lower_bound(ny+1,ny+n+1,y[i])-ny; return ( (tmpx*x[i]-sumx[tmpx]+sumx[n]-sumx[tmpx]-(n-tmpx)*x[i]) ) + ( tmpy*y[i]-sumy[tmpy]+sumy[n]-sumy[tmpy]-(n-tmpy)*y[i] ); } void work() { scanf("%lld",&n); for(long long i=1,a,b;i<=n;i++) { scanf("%lld%lld",&a,&b); x[i]=nx[i]=a+b; y[i]=ny[i]=a-b; } sort(nx+1,nx+n+1); sort(ny+1,ny+n+1); for(long long i=1;i<=n;i++) { sumx[i]=sumx[i-1]+nx[i]; sumy[i]=sumy[i-1]+ny[i]; } ans=0x7ffffffffffff; for(long long i=1;i<=n;i++) { ans=min(ans,calc(i)); } printf("%lld",ans>>1); } } int main() { zzc::work(); return 0; }