码迷,mamicode.com
首页 > 移动开发 > 详细

hdu5406 CRB and Apple dp+两个LIS

时间:2016-07-03 00:25:55      阅读:185      评论:0      收藏:0      [点我收藏+]

标签:

去年多校的题,很久以前就想补了,奈何智商有限,当初连题解代码都看不懂。

—————————————————————————————————————————————————————————————————————

题意转换为:给定n个数,求两个最长的不相交的LIS。

先说经典题一个LIS的nlogn做法。枚举当前数,若比末尾数大,插入末尾,否则二分查找,插入合适位置。

通过此题,我们有了一个用树状数组或线段树+dp解决LIS的方法。

首先离散化。dp[n]表示末尾数为n时的LIS的长度。

for循环枚举数列中的数i,dp[i] = max(dp[j])+1, j <= i

max的值可以用树状数组或线段树logn复杂度解决,总复杂度依然是nlogn。

咦,用树状数组也能解决?

树状数组两个操作,单点修改,前缀查询。

我们发现,dp[i]的值是单调不减的。每次修改,都可以用树状数组向上传递更新。(如果dp[i]的值会变小,就无法向上传递更新了。)

而我们查询的满足j <= i刚好是前缀查询。

树状数组完美解决。

—————————————————————————————————————————————————————————————————————

言归正传。

两个LIS如何解决?

dp[i][j]表示当前两个LIS末尾为i和j时的dp值。

dp[i][j] = max(dp[i][k])+1, k <= j;

我们只要先将答案存在一个数组里,然后统一更新dp数组的行值与列值即可。

技术分享
 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstring>
 5 using namespace std;
 6 
 7 struct p{
 8     int h, d;
 9     p(){}
10     p(int h, int d):h(h), d(d){}
11     bool operator <(const p& x) const{
12         return h != x.h? h > x.h : d < x.d;
13     }
14 };
15 p pp[1005];
16 int s[2005];
17 int dp[1005][1005], tmp[1005];
18 
19 void add(int* a, int x, int d){
20     for(int i = x; i < 1005; i += i&-i)
21         a[i] = max(a[i], d);
22 }
23 int sum(int* a, int x){
24     int ret = 0;
25     for(int i = x; i; i -= i&-i)
26         ret = max(ret, a[i]);
27     return ret;
28 }
29 
30 int main(){
31     int t, n; scanf("%d", &t);
32     while(t--){
33         scanf("%d", &n);
34         for(int i = 0; i < n; i++){
35             scanf("%d%d", &pp[i].h, &pp[i].d);
36             s[i] = pp[i].d;
37         }
38         sort(pp, pp+n);
39         sort(s, s+n);
40         for(int i = 0; i < n; i++)
41             pp[i].d = lower_bound(s, s+n, pp[i].d)-s+1;
42 
43         memset(dp, 0, sizeof(dp));
44         int ans = 0;
45         for(int i = 0; i < n; i++){
46             int v = pp[i].d;
47             for(int j = 1; j <= n; j++){
48                 tmp[j] = sum(dp[j], v)+1;
49                 ans = max(ans, tmp[j]);
50             }
51             for(int j = 1; j <= n; j++){
52                 add(dp[j], v, tmp[j]);
53                 add(dp[v], j, tmp[j]);
54             }
55         }
56         printf("%d\n", ans);
57     }
58     return 0;
59 }
View Code

 

hdu5406 CRB and Apple dp+两个LIS

标签:

原文地址:http://www.cnblogs.com/dirge/p/5636316.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!