AtCoder Beginner Contest 230 D - Destroyer Takahashi
阿新 • • 發佈:2021-12-16
題意
給定N堵牆,一拳超人每次選一個範圍攻擊,如果某個牆有任意一格在這個範圍內,這堵牆就銷燬了。
求:最小的揮拳數量
題解
條件1:要打掉所有牆。
條件2:揮拳數量要儘量小。
條件3:一次揮拳只能銷燬一定範圍內的牆。
性質1:在揮拳數量儘量小的情況下,所有牆必須被銷燬。
性質2:如果兩次揮拳能夠合併成一次揮拳且滿足性質1,就應當計數為1。
性質3:揮拳一定是有邏輯、有順序的。
答案1:應當對所有牆以左端點為主鍵,右端點為次鍵排序。(條件3/性質3/性質1)
反證1:不能直接對每個牆的右端點進行攻擊,因為一個大牆可以覆蓋整個區間。
答案2:定義minR為一定範圍內能夠攻擊的牆的右端點的最小值,那麼[minR,minR+D-1]就是能夠摧毀的牆的左端點的合法取值區間。(性質1/性質2)
複雜度:{O(n),O(n)}
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; const int MAXN = 4e5; struct Wall { int l, r; bool operator <(const Wall &another)const { if (l == another.l)return r < another.r; return l < another.l; } }s[MAXN]; int main() { int n, D; scanf("%d%d", &n, &D); for (int i = 1; i <= n; i++) { scanf("%d%d", &s[i].l, &s[i].r); } sort(s + 1, s + n + 1); int cnt = 0; for (int i = 1; i <= n;i++) { int minR=s[i].r; cnt++; for (int j = i + 1;s[j].l<=minR+D-1&&j<=n; j++) { minR = min(minR, s[j].r); i = j; } } printf("%d\n", cnt); return 0; }