洛谷P1020 导弹拦截

n²谁都会打,不说了。

这里讨论一下nlogn算法(单调不减):

首先开始考虑单调性,我习惯性的以为是单调队列/栈优化的那个套路,想要找到一个跟下标有关的单调性却发现没有。

例如:我想过当下标增加时f[i]增加,后来发现了反例:1 3 4 2

事实上也没有别的想得到的了。

我跑去看题解,发现单调性是这个毒瘤:

当单调不减子序列长度增加时,每个长度对应的最小高度增加。

然后每次二分出一个长度,保证最小高度刚好不大于a[i]

然后用a[i]更新f[i]的最小高度...

然后就没啥难点了,A了。

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <cstring>
 4 
 5 const int N = 100010;
 6 
 7 int a[N], f[N], p[N], top;
 8 
 9 inline int BS(int x) {
10     int l = 0, r = top, mid;
11     while(l < r) {
12         mid = (l + r + 1) >> 1;
13         if(p[mid] < x) {
14             r = mid - 1;
15         }
16         else {
17             l = mid;
18         }
19     }
20     return r;
21 }
22 
23 inline int BS2(int x) {
24     int l = 0, r = top, mid;
25     while(l < r) {
26         mid = (l + r + 1) >> 1;
27         if(p[mid] >= x) {
28             r = mid - 1;
29         }
30         else {
31             l = mid;
32         }
33     }
34     return r;
35 }
36 
37 int main() {
38     int n = 0, x;
39     while(scanf("%d", &x) != -1) {
40         a[++n] = x;
41     }
42     for(int i = 1; i <= n; i++) {
43         int t = BS(a[i]);
44         f[i] = t + 1;
45         p[f[i]] = std::max(p[f[i]], a[i]);
46         top = std::max(top, f[i]);
47     }
48     printf("%d \n", top);
49     top = 0;
50     memset(p, 0x7f, sizeof(p));
51     for(int i = 1; i <= n; i++) {
52         int t = BS2(a[i]);
53         f[i] = t + 1;
54         p[f[i]] = std::min(p[f[i]], a[i]);
55         top = std::max(top, f[i]);
56     }
57     printf("%d", top);
58     return 0;
59 }
AC代码

附一张提交记录

 

posted @ 2018-07-11 17:19  garage  阅读(105)  评论(0编辑  收藏  举报