1. 程式人生 > >BZOJ3170: [Tjoi2013]松鼠聚會 - 暴力

BZOJ3170: [Tjoi2013]松鼠聚會 - 暴力

line cor main amp 聚會 getchar efi 上下左右 描述

描述

有N個小松鼠,它們的家用一個點x,y表示,兩個點的距離定義為:點(x,y)和它周圍的8個點即上下左右四個點和對角的四個點,距離為1。現在N個松鼠要走到一個松鼠家去,求走過的最短距離。

題解

簡直就是個高中數學題啊。。。蒟蒻數學不好,學不來嗚

松鼠$i $ 和 $j$ 的距離為$ \max{\left\vert X_i - X_j \right\vert, \left\vert Y_i - Y_j\right\vert } $

但是我們不能在很短的時間內求出對於所有$i$和$j$ 的$\max$, 所以只能通過加絕對值讓$\max$去掉。

首先1. $\max{a, b} = (\left\vert a + b\right\vert + \left\vert a - b\right\vert) \div 2$

並且 2.$ \left\vert \left\vert a\right\vert - \left\vert b\right\vert \right\vert + \left\vert \left\vert a\right\vert + \left\vert b\right\vert \right\vert = \left\vert a - b\right\vert + \left\vert a + b\right\vert$

我們通過式子1算出$ \max{\left\vert X_i - X_j \right\vert, \left\vert Y_i - Y_j\right\vert } = ( \left\vert \left\vert X_i - X_j \right\vert - \left\vert Y_i - Y_j\right\vert \right\vert + \left\vert \left\vert X_i - X_j \right\vert + \left\vert Y_i - Y_j \right\vert \right\vert ) \ div 2$

然後再通過2式就變成了 $( \left\vert ( X_i-Y_i ) - (X_j - Y_j) \right\vert + \left\vert (X_i - Y_i) + (X_j - Y_j) \right\vert) \div 2$

令$a_i = X_i - Y_i $ $b_i = X_i + Y_i$

算出所有的$\left\vert a_i - a_j \right\vert $ 和$\left\vert b_i - b_j\right\vert$ 再除 2, 取答案最小的$i$

算$\left\vert a_i - a_j \right\vert $ 時需要排序求前綴和計算。

打絕對值累死我了。。、

代碼

技術分享圖片
 1 #include<cstring>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #define rd read()
 5 #define ll long long
 6 using namespace std;
 7 
 8 const int N = 2e5;
 9 
10 ll sumx[N], sumy[N], n, ans = 1e18;
11 
12 struct node {
13     ll x, y;
14     ll xx, yy;
15     ll disx, disy;
16 }a[N];
17 
18 ll read() {
19     ll X = 0, p = 1; char c = getchar();
20     for(; c > 9 || c < 0; c = getchar()) if(c == -) p = -1;
21     for(; c >= 0 && c <= 9; c = getchar()) X = X * 10 + c - 0;
22     return X * p;
23 }
24 
25 int cmpx(const node &A, const node &B ) {
26     return A.xx < B.xx;
27 }
28 
29 int cmpy(const node &A, const node &B) {
30     return A.yy < B.yy;
31 }
32 
33 int main()
34 {
35     n = rd;
36     for(int i = 1; i <= n; ++i) {
37         a[i].x = rd * 2;
38         a[i].y = rd * 2;
39         a[i].xx = (a[i].x + a[i].y) >> 1;
40         a[i].yy = (a[i].x - a[i].y) >> 1;
41     }
42     sort(a+1, a+1+n, cmpx);
43     for(int i = 1; i <= n; ++i) sumx[i] = sumx[i - 1] + a[i].xx;
44     for(int i = 1; i <= n; ++i) {
45         a[i].disx = a[i].xx * i - sumx[i];
46         a[i].disx += sumx[n] - sumx[i] - (n - i) * a[i].xx;
47     }
48     sort(a+1, a+1+n, cmpy);
49     for(int i = 1; i <= n; ++i) sumy[i] = sumy[i - 1] + a[i].yy;
50     for(int i = 1; i <= n; ++i) {
51         a[i].disy = a[i].yy * i - sumy[i];
52         a[i].disy += sumy[n] - sumy[i] - (n - i) * a[i].yy;
53         if(a[i].disy + a[i].disx < ans) ans = a[i].disx + a[i].disy;
54     }
55     printf("%lld\n", ans >> 1);
56 }
View Code

BZOJ3170: [Tjoi2013]松鼠聚會 - 暴力