# 進階班選幹題解 --- ## ZJ c575: APCS 2017-0304-4基地台 ### 題目簡介 給定數個服務台的一維座標 `arr[n]`及基地台個數 `k`,輸出基地台最小直徑為何? (所有基地台服務直徑相等) --- ### 想法 - 先把服務台座標 $sort$ 過,後續處理較輕鬆 - 每種直徑最少需要幾個基地台 - 基地台個數 `<=k` 且直徑最小 - <font color="#9A9898">~~*暴搜直徑真好寫*~~</font> 使用二分搜找直徑 ---> $O(n^2)$ -> $O(nlgn)$ --- ### 程式碼 ```cpp= sort(v.begin(), v.end()); while (dl != dr - 1) { int x, tmp = v[0]; for (x = 0; x < p; x++) { tmp += dm; if (tmp >= v[v.size() - 1]) {ans = dm, dr = dm; break;} tmp = *upper_bound(v.begin(), v.end(), tmp); } if (x == p) dl = dm; dm = (dl + dr) >> 1; if (dm == 1) dl = 0; } cout << ans << '\n'; return 0; } ``` --- ## DJ a139: 二維偏序問題 ### 題目簡介 給定二維座標點集 $P$,依序對第 $i$ 個點 $(x_i, y_i)$ 輸出 $P$ 中 $x_i<x_j$ 且 $y_i<y_j$ 之 $(x_j,y_j)$ 個數。 --- ### 想法 - 先對第一維座標 $sort$ 過後,對第二維座標做順序數對 - 因為 $sort$ 會讓點順序跑掉,所以刻一個 $struct$ 存位置 - 注意第一維或第二維座標相等的點不能算進去 --- ### 程式碼 ```cpp= struct dot { int x, y, pos; bool operator<(dot d) {return ((x < d.x) || (x == d.x && y < d.y) ||(x == d.x && y == d.y && pos < d.pos));} }; void merge_sort(vector<dot>& v, vector<int>& time) { if (v.size() != 1) { merge_sort(left, time), merge_sort(right, time); size_t l = 0, r = 0, x = 0; while (l != left.size() && r != right.size()) { if (left[l].y > right[r].y || (left[l].y == right[r].y && left[l].x < right[r].x)) { v[x] = left[l], l++; time[v[x].pos] += r; } else v[x] = right[r], r++; x++; } while (l != left.size()) v[x] = left[l], l++, time[v[x].pos] += r, x++; while (r != right.size()) v[x] = right[r], r++, x++; } else return; } int main(){ for (int x = 0; x < n; x++) cin>>v[x].x>>v[x].y,v[x].pos = x; sort(v.begin(), v.end()); vector<int> time(n, 0); for (int x = n - 1; x >= 0; x--) { if (tmp != v[x].x) tmp = v[x].x, cnt = 0; else cnt++, time[v[x].pos] -= cnt; } merge_sort(v, time); for (auto&i : time) cout << i << '\n'; return 0; } ```