Solution -「營業」「CF567D」One-Dimensional Battle Ships
阿新 • • 發佈:2021-07-08
題目大意 - 翻譯
Alice 和 Bob喜歡在 \(1\times n\) 的表格中玩戰艦遊戲。遊戲開始時,Alice 有 \(k\) 艘戰艦,每艘戰艦長度為 \(a\),她需要把這些戰艦不重疊且不相鄰地放在格子中(不允許有兩艘戰艦的格子存在公共邊)。但她並不會告訴 Bob 她放的位置。
接下來,Bob 會用 \(m\) 顆炮彈嘗試打中 Alice 的戰艦,每顆炮彈會選擇一個格子打擊。但由於 Alice 喜歡作弊,所以她不會告訴 Bob 什麼時候擊中了戰艦。請你幫助 Bob 判斷,在第幾次發射炮彈後,Alice 一定會有一艘戰艦被擊中。
分析
不難看出整個問題是具有單調性的,即炮彈打出的越多就越有可能達成“戰艦肯定被打到了”這一成就。那麼就直接考慮 二分答案
當我們列舉到一個 mid 的時候,我們將所有在 mid 之前發射的炮彈對應到原表格上。得到的效果即原表格被分成了很多個區間。
在這樣的情況下如果我們考慮每一個區間的左端都被戰艦佔據(或不被佔),且右端一定不被佔據。則這樣的放置方法一定是合法的,且對於每一個區間,最多可以放 \(\frac{r - l}{a + 1}\) 艘戰艦。
那麼就可以求到在 mid 之前的所有炮彈打出的情況下,最多能保證多少戰艦不被打到。顯然如果這個個數小於 k ,這個答案就一定可以為最後答案。
當然因為我們要找的是最小的,所以在這個時候就繼續往小的找咯。
#include <cstdio> #include <algorithm> using namespace std; int Max(int x, int y) {return x > y ? x : y;} int Min(int x, int y) {return x < y ? x : y;} int Abs(int x) {return x < 0 ? -x : x;} int read() { int k = 1, x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') k = -1; s = getchar(); } while (s >= '0' && s <= '9') { x = (x << 3) + (x << 1) + s - '0'; s = getchar(); } return x * k; } void write(int x) { if(x < 0) { putchar('-'); x = -x; } if(x > 9) write(x / 10); putchar(x % 10 + '0'); } void print(int x, char s) { write(x); putchar(s); } const int MAXN = 2e5 + 5; struct node { int id, val; node() {} node(int Id, int Val) { id = Id; val = Val; } } q[MAXN]; bool cmp(node x, node y) { return x.val < y.val; } int n, k, a, m; bool check(int mid) { int ans = 0, last = 0; for(int i = 1; i <= m; i++) if(q[i].id <= mid) { ans += ((q[i].val - last) / (a + 1)); last = q[i].val; } ans += ((n - last + 1) / (a + 1)); return ans < k; } int main() { n = read(), k = read(), a = read(), m = read(); for(int i = 1; i <= m; i++) { q[i].val = read(); q[i].id = i; } sort(q + 1, q + m + 1, cmp); int l = 1, r = m, res = -1; while(l <= r) { int mid = (l + r) >> 1; if(check(mid)) { res = mid; r = mid - 1; } else l = mid + 1; } print(res, '\n'); return 0; }