洛谷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 }
附一张提交记录