[POJ1631]Bridging signals (DP,二分优化)

题目链接:http://poj.org/problem?id=1631

  就是求一个LIS,但是范围太大(n≤40000),无法用常规O(n²)的朴素DP算法,这时需要优化。

  新加一个数组s[]来维护长度当LIS的长度为len时候需要的数组a中的最小数字的值,可以证明这个数组是严格单调递增的,因此可以二分确定每次枚举到a[i]的时候,a[i]在这个数组中所处的位置(下标),也就是a[i]数字时此时之前算过的LIS的长度。之后更新s数组和ans即可。对于最长下降自序列此方法同样适用,但是需要注意那时s数组是严格单调递减的,并且更新s数组的时候也要尽可能地取大值。

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <iomanip>
 4 #include <cstring>
 5 #include <climits>
 6 #include <complex>
 7 #include <fstream>
 8 #include <cassert>
 9 #include <cstdio>
10 #include <bitset>
11 #include <vector>
12 #include <deque>
13 #include <queue>
14 #include <stack>
15 #include <ctime>
16 #include <set>
17 #include <map>
18 #include <cmath>
19 
20 using namespace std;
21 
22 const int maxn = 40010;
23 int n;
24 int dp[maxn];
25 int s[maxn];
26 int a[maxn];
27 
28 int bs(int ll, int rr, int v) {
29     while(ll <= rr) {
30         int mm = (ll + rr) >> 1;
31         if(s[mm] <= v) ll = mm + 1;
32         else rr = mm - 1;
33     }
34     return ll;
35 }
36 
37 int main() {
38     // freopen("in", "r", stdin);
39     int T;
40     scanf("%d", &T);
41     while(T--) {
42         scanf("%d", &n);
43         for(int i = 1; i <= n; i++) {
44             scanf("%d", &a[i]);
45         }
46         memset(dp, 0, sizeof(dp));
47         memset(s, 0x7f7f7f7f, sizeof(s));
48         // for(int i = 1; i <= n; i++) {
49         //     dp[i] = 1;
50         //     for(int j = 1; j < i; j++) {
51         //         if(a[i] > a[j] && dp[i] < dp[j] + 1) {
52         //             dp[i] = dp[j] + 1;
53         //         }
54         //     }
55         //     ans = max(dp[i], ans);
56         // }
57         int ans = 0;
58         for(int i = 1; i <= n; i++) {
59             dp[i] = bs(1, i, a[i]);
60             printf("%d ", dp[i]);
61             s[dp[i]] = min(s[dp[i]], a[i]);
62             ans = max(ans, dp[i]);
63         }
64         printf("
");
65         printf("%d
", ans);
66     }
67     return 0;
68 }
原文地址:https://www.cnblogs.com/kirai/p/5398350.html