[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("\n");
65         printf("%d\n", ans);
66     }
67     return 0;
68 }
时间: 2024-10-18 10:08:13

[POJ1631]Bridging signals (DP,二分优化)的相关文章

zoj1986 Bridging Signals (dp,最长递增序列,LIS)

A - Bridging Signals Time Limit:2000MS Memory Limit:65536KB 64bit IO Format:%lld & %llu Submit Status Practice ZOJ 1986 Description 'Oh no, they've done it again', cries the chief designer at the Waferland chip factory. Once more the routing designer

hdoj 1950 Bridging signals【二分求最大上升子序列长度】

Bridging signals Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 961    Accepted Submission(s): 627 Problem Description 'Oh no, they've done it again', cries the chief designer at the Waferland

poj1631 Bridging signals

思路: LIS,二分. 实现: 1 #include <cstdio> 2 #include <iostream> 3 using namespace std; 4 int d[40010]; 5 int fuck(int x, int right) 6 { 7 int left = 0; 8 int pos = -1; 9 while (left <= right) 10 { 11 int middle = (left + right) / 2; 12 if (d[midd

POJ-1631 Bridging signals

题目大意:就是求最长的上升子序列,输出长度. 思路:LIS水题.就是题目描述的特别长. 1 #include<iostream> 2 #include<stdio.h> 3 #include<algorithm> 4 #include<string.h> 5 using namespace std; 6 int a[40005]; 7 int dp[40005]; 8 int mx[40005]; 9 int INF=9999999; 10 int main

poj 1631 Bridging signals DP(最长上升子序列)

最近一直在做<挑战程序设计竞赛>的练习题,感觉好多经典的题,都值得记录. 题意:给你t组数据,每组数组有n个数字,求每组的最长上升子序列的长度. 思路:由于n最大为40000,所以n*n的复杂度不够了,会超时. 书上状态方程换成了d[i]——以长度为i+1的上升子序列中末尾元素的最小值. 那么我们在遍历第i个元素时候,以这个元素为末尾元素的最长子序列也就是在d[i]中找到一个小于num[i]的最大值,然后在这个序列末尾加上num[i] 显然,我们在查找时便可以利用二分搜索,从而把复杂度从原来的

POJ 1631 Bridging signals(LIS+二分)

题目链接:POJ 1631 Bridging signals [题意]简单来说就是求最长上升子序列的长度. [思路]这道题目的数据规模有40000之多,如果用普通的动态规划O(n^2)肯定会超时的,所以要用上二分查找(又是二分啊,真牛逼)来进行优化,O(nlogn)的时间复杂度就OK了. 我使用了C++的lower_bound(ForwardIter first, ForwardIter last, const _Tp& val)函数.可以直接查找非递减序列[first, last)中的第一个大

POJ-2533最长上升子序列(DP+二分)(优化版)

Longest Ordered Subsequence Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 41944   Accepted: 18453 Description A numeric sequence of ai is ordered if a1 < a2 < ... < aN. Let the subsequence of the given numeric sequence (a1, a2, ...

硬币问题 (dp,多重背包的二分优化)

题目描述 给你n种硬币,知道每种的面值Ai和每种的数量Ci.问能凑出多少种不大于m的面值. 输入 有多组数据,每一组第一行有两个整数 n(1≤n≤100)和m(m≤100000),第二行有2n个整数,即面值A1,A2,A3,…,An和数量C1,C2,C3,…,Cn (1≤Ai≤100000,1≤Ci≤1000).所有数据结束以2个0表示. 输出 每组数据输出一行答案. 样例输入 3 10 1 2 4 2 1 1 2 5 1 4 2 1 0 0 样例输出 8 4 背包问题的复杂度是n*m,这题如果

POJ 1631 Bridging signals(LIS 二分 快速方法)

Language: Default Bridging signals Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 10762   Accepted: 5899 Description 'Oh no, they've done it again', cries the chief designer at the Waferland chip factory. Once more the routing designers