題解 P1020 飛彈攔截

2022-05-02 04:15:11 字數 2675 閱讀 7890

某國為了防禦敵國的飛彈襲擊,發展出一種飛彈攔截系統。但是這種飛彈攔截系統有乙個缺陷:雖然它的第一發炮彈能夠到達任意的高度,但是以後每一發炮彈都不能高於前一發的高度。某天,雷達捕捉到敵國的飛彈來襲。由於該系統還在試用階段,所以只有一套系統,因此有可能不能攔截所有的飛彈。

輸入飛彈依次飛來的高度(雷達給出的高度資料是 \le 50000≤50000的正整數),計算這套系統最多能攔截多少飛彈,如果要攔截所有飛彈最少要配備多少套這種飛彈攔截系統。

資料範圍:

子問題1:n <= 1000

子問題2:n <= 100000

思路:序列dp +線段樹優化dp

首先第乙個問題,其實就是求最長不上公升序列。

我們設計 dp[i] 為從 1 到 i且其最長不上公升序列以 i 為結尾的序列長度。那麼我們可以從比當顆飛彈高或相等的飛彈中更新答案。即為:

dp[i] = max + 1 (a[v] >= a[i] && v <= i)
這裡時間複雜度為o(n^2)。

對於第二個問題,我們可以想到,假如我們先用乙個攔截設施把所有能打下來的飛彈都打下來,剩下的攔截設施重複這個動作,一直到所有飛彈被攔截。假設我們得到的是最小劃分(題目要求)的k組飛彈。那麼對於第 i 組飛彈中任取,在第 i + 1 必定有乙個飛彈要比這顆飛彈高,如果沒有,那麼我們完全可以把 i + 1 組合並到第 i 組。所以我們找到乙個最長的乙個上公升子串行,肯定序列中的每個飛彈對應組飛彈,如果多出的話肯定是多餘的,如果少的話,不符合上述的分組。所以我們在找最小劃分時,只需要找到乙個最長上公升子串行長度即可。

我們重新設計 dp[i] 為從 1 到 i且其最長上公升子串行以 i 為結尾的序列長度。同上,我們可以得到:

dp[i] = max + 1 (a[v] < a[i] && v <= i)
時間複雜度也為o(n^2)

對於優化:(兩問通用)

時間複雜度為o(nlogn)

p.s. **中注釋掉的是沒優化時的部分**

#include#include#include#include#include#include#include#include#include#include#includeusing namespace std;

#define go(i, j, n, k) for(int i = j; i <= n; i += k)

#define fo(i, j, n, k) for(int i = j; i >= n; i -= k)

#define rep(i, x) for(int i = h[x]; i; i = e[i].nxt)

#define mn 100010

#define inf 1 << 30

#define ll long long

#define root 1, 50000, 1

#define lson l, m, rt << 1

#define rson m + 1, r, rt << 1 | 1

#define bson l, r, rt

inline int read()

while(ch >= '0' && ch <= '9')

return x * f;

}int minn[mn << 2], maxx[mn << 2];

inline void update(int rt)

inline void build(int l, int r, int rt)

int m = (l + r) >> 1; build(lson), build(rson), update(rt);

}inline void modify(int l, int r, int rt, int now, int v)

int m = (l + r) >> 1;

if(now <= m) modify(lson, now, v);

else modify(rson, now, v);

update(rt);

}inline int query(int l, int r, int rt, int nowl, int nowr) else return query(rson, nowl, nowr);

}int f[mn], a[mn], n, ans1, ans2;

int main()

// }

maxx = query(root, a[i], 50000);

f[i] = maxx + 1;

modify(root, a[i], f[i]);

ans1 = max(f[i], ans1);

} cout << ans1 << "\n";

go(i, 1, n, 1) f[i] = 0;

build(root);

go(i, 1, n, 1)

// }

maxx = query(root, 1, a[i] - 1);

f[i] = maxx + 1;

modify(root, a[i], f[i]);

ans2 = max(f[i], ans2);

} cout << ans2 << "\n";

return 0;

}

P1020 飛彈攔截 題解

100題解 第二問dilworth定理 對於乙個偏序集,最少鏈劃分等於最長反鏈長度。dilworth定理的對偶定理 對於乙個偏序集,其最少反鏈劃分數等於其最長鏈的長度。也就是說把乙個數列劃分成最少的最長不公升子串行的數目就等於這個數列的最長上公升子串行的長度。include include defi...

P1020 飛彈攔截

題目描述 某國為了防禦敵國的飛彈襲擊,發展出一種飛彈攔截系統。但是這種飛彈攔截系統有乙個缺陷 雖然它的第一發炮彈能夠到達任意的高度,但是以後每一發炮彈都不能高於前一發的高度。某天,雷達捕捉到敵國的飛彈來襲。由於該系統還在試用階段,所以只有一套系統,因此有可能不能攔截所有的飛彈。輸入飛彈依次飛來的高度...

P1020 飛彈攔截

某國為了防禦敵國的飛彈襲擊,發展出一種飛彈攔截系統。但是這種飛彈攔截系統有乙個缺陷 雖然它的第一發炮彈能夠到達任意的高度,但是以後每一發炮彈都不能高於前一發的高度。某天,雷達捕捉到敵國的飛彈來襲。由於該系統還在試用階段,所以只有一套系統,因此有可能不能攔截所有的飛彈。輸入飛彈依次飛來的高度 雷達給出...