題目描述
草原上住着一羣小松鼠,每個小松鼠都有一個家。時間長了,大家覺得應該聚一聚。但是草原非常大,松鼠們都很頭疼應該在誰家聚會才最合理。
每個小松鼠的家可以用一個點x,y表示,兩個點的距離定義爲點(x,y)和它周圍的8個點(x-1,y)(x+1,y),(x,y-1),(x,y+1).(x-1,y+1),(x-1,y-1),(x+1,y+1),(x+1,y-1)距離爲1。
30%的數據,0 ≤ N ≤ 1000
100%的數據,0 ≤ N ≤ 100000; −10^9 ≤ x, y ≤ 10^9
輸入輸出格式
輸入格式:
第一行是一個整數N,表示有多少隻松鼠。接下來N行,第i行是兩個整數x和y,表示松鼠i的家的座標
輸出格式:
一個整數,表示松鼠爲了聚會走的路程和最小是多少。
輸入輸出樣例
輸入樣例#1:
6
-4 -1
-1 -2
2 -4
0 2
0 3
5 -2輸出樣例#1:
20
輸入樣例#2:
6
0 0
2 0
-5 -2
2 -2
-1 2
4 0輸出樣例#2:
15
思路:
本題實質是給出 n 個點,找出一個點 x,然後使得其他 n-1 個點到 x 的切比雪夫距離最小,之後求距離和的最小值
而需要求 n 個點切比雪夫距離的和時,由於要窮舉其他 n-1 個點到當前點的距離,即計算:
可以發現,每次計算距離都要取 max,每次都是一個 O(n) 的計算過程,總時間複雜度可達 O(n^2),複雜度太高,而曼哈頓距離只有求和與取絕對值兩種運算,因此我們可以考慮將切比雪夫距離轉化爲曼哈頓距離,然後利用前綴和優化,進而降低時間複雜度。
設 爲從 i 到 j 曼哈頓距離,那麼有:,複雜度仍是 O(n^2)
進一步化簡,有:
同時以 dis(i,j) 中的一部分 舉例化簡,有:
若先將橫座標處理爲遞增的,那麼易得 前的部分是可以繼續拆絕對值化簡的, 後的部分是 的,因此進一步可化簡爲:
可以發現上式子是一個前綴和,而 部分與上式同理,因此我們只需要維護有序狀態下 與 的值即可。
此時,各步驟的時間複雜度如下:
- 座標變換:O(n)
- 前綴和處理:O(n)
- 枚舉每個點:O(n)
- 計算一個點的答案:O(log n)
總時間複雜度即爲:O(nlog n),相較於之前的 O(n^2),已有了極大的優化。
源代碼
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<bitset>
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LL long long
#define Pair pair<int,int>
LL quickPow(LL a,LL b){ LL res=1; while(b){if(b&1)res*=a; a*=a; b>>=1;} return res; }
LL multMod(LL a,LL b,LL mod){ a%=mod; b%=mod; LL res=0; while(b){if(b&1)res=(res+a)%mod; a=(a<<=1)%mod; b>>=1; } return res%mod;}
LL quickMultPowMod(LL a, LL b,LL mod){ LL res=1,k=a; while(b){if((b&1))res=multMod(res,k,mod)%mod; k=multMod(k,k,mod)%mod; b>>=1;} return res%mod;}
LL quickPowMod(LL a,LL b,LL mod){ LL res=1; while(b){if(b&1)res=(a*res)%mod; a=(a*a)%mod; b>>=1; } return res; }
LL getInv(LL a,LL mod){ return quickPowMod(a,mod-2,mod); }
LL GCD(LL x,LL y){ return !y?x:GCD(y,x%y); }
LL LCM(LL x,LL y){ return x/GCD(x,y)*y; }
const double EPS = 1E-6;
const int MOD = 1000000000+7;
const int N = 100000+5;
const int dx[] = {0,0,-1,1,1,-1,1,1};
const int dy[] = {1,-1,0,0,-1,1,-1,1};
using namespace std;
struct Node {
LL x, y;
} node[N];
int n, x[N], y[N];
LL sum1[N], sum2[N];
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
int a, b;
scanf("%d%d", &a, &b);
x[i] = node[i].x = a + b;
y[i] = node[i].y = a - b;
}
sort(x + 1, x + n + 1);
sort(y + 1, y + n + 1);
for (int i = 1; i <= n; i++){
sum1[i] = sum1[i - 1] + x[i];
sum2[i] = sum2[i - 1] + y[i];
}
LL res=1ll << 62;
for (int i = 1; i <= n; i++) {
int pos = lower_bound(x + 1, x + n + 1, node[i].x) - x;
LL sum = sum1[n] - sum1[pos] - node[i].x * (n - pos) + node[i].x * pos - sum1[pos];
pos = lower_bound(y + 1, y + n + 1, node[i].y) - y;
sum += sum2[n] - sum2[pos] - node[i].y * (n - pos) + node[i].y * pos - sum2[pos];
res = min(res, sum);
}
printf("%lld\n", res / 2);
return 0;
}