SGU 199 Beautiful People 二维最长递增子序列

题目链接:

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=20885

题意:

求二维最长严格递增子序列。

题解:

O(n^2)的算法很好想,不过这里会t掉,只能O(nlogn)

于是用二分来维护:

先把所有的数按x递增排序,x相同的按y递减排序(这里之所以要按y递减排序是因为为了写代码方便,递减的话你后面基本就只要考虑y的大小,如果不递减,你还要考虑x的大小的,具体的可以自己思考一下)

排完序之后我们接下来就只考虑y的大小,我们维护一个目前长度为len的最长子序列,并且它的value取目前所有长度为len的最长子序列中,以最小y结尾的那个y值。

然后我们会发现我们维护的这些长度的value是随长度变大递增的!!!(这个可以证明!),于是就可以用二分来找能接在当前的那个人后面的最长的长度。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7
 8 const int maxn = 1e5 + 10;
 9
10 struct Node {
11     int x, y,id;
12     bool operator < (const Node& tmp) const {
13         return x < tmp.x||x==tmp.x&&y>tmp.y;
14     }
15 }arr[maxn];
16
17 int n,maxlen;
18 int pre[maxn],dp[maxn],yy[maxn];
19
20 void init() {
21     memset(pre, -1, sizeof(pre));
22     maxlen = 0;
23 }
24
25 int main() {
26     while (scanf("%d", &n) == 1 && n) {
27         init();
28         for (int i = 0; i < n; i++) {
29             scanf("%d%d", &arr[i].x, &arr[i].y);
30             arr[i].id = i + 1;
31         }
32         sort(arr, arr + n);
33         dp[0] = 1; yy[++maxlen] = 0;
34         for (int i = 1; i < n; i++) {
35             int low = 1, hig = maxlen+1;
36             if (arr[i].y <= arr[yy[low]].y) {
37                 yy[low] = i;
38                 continue;
39             }
40             while (low + 1 < hig) {
41                 int mid = low + (hig - low) / 2;
42                 if (arr[yy[mid]].y < arr[i].y) low = mid;
43                 else hig = mid;
44             }
45             pre[i] = yy[low];
46             int len = low + 1;
47             if (len > maxlen) {
48                 yy[++maxlen] = i;
49             }
50             else {
51                 if (arr[i].y < arr[yy[len]].y) yy[len] = i;
52             }
53         }
54         vector<int> ans;
55         int p = yy[maxlen];
56         while (p != -1) {
57             ans.push_back(p);
58             p = pre[p];
59         }
60         printf("%d\n", ans.size());
61         for (int i = 0; i < ans.size() - 1; i++) printf("%d ", arr[ans[i]].id);
62         printf("%d\n", arr[ans[ans.size() - 1]].id);
63     }
64     return 0;
65 }

还有一种复杂的解决方法,用二分查找符合区间,然后用线段树查区间最大值。

待续。。。

时间: 2024-10-13 10:36:22

SGU 199 Beautiful People 二维最长递增子序列的相关文章

SGU 199. Beautiful People 二维LIS

第一维排序 第二维LIS #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int dp[100010]; int p[100010]; struct node { int x, y, id; }a[100010]; bool cmp(node a, node b) { if(a.x != b.x) return a.x < b.x; return a.y

UVa 10285 Longest Run on a Snowboard(DP 二维最长递减子序列)

题意  输入一个城市的滑雪地图  你可以从高的地方滑到伤下左右低的地方  求这个城市的最长滑雪线路长度   即在一个矩阵中找出最长递减连续序列 令d[i][j]为以格子map(i,j)为起点的最长序列   则有状态转移方程d[i][j]=max{d[a][b]}+1  a,b为与i,j相邻且值比i,j小的所有点 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #def

[poj1088]滑雪(二维最长下降子序列)

解题关键:记忆化搜索 #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<iostream> #include<cmath> using namespace std; typedef long long ll; int d[102][102],n,m; int dp[102][102]; int dir[4][2]={0,1

51nod 1376: 最长递增子序列的数量(二维偏序+cdq分治)

1376 最长递增子序列的数量 Time Limit: 1 Sec Memory Limit: 128MB 分值: 160 难度:6级算法题 Description 数组A包含N个整数(可能包含相同的值).设S为A的子序列且S中的元素是递增的,则S为A的递增子序列.如果S的长度是所有递增子序列中最长的,则称S为A的最长递增子序列(LIS).A的LIS可能有很多个.例如A为:{1 3 2 0 4},1 3 4,1 2 4均为A的LIS.给出数组A,求A的LIS有多少个.由于数量很大,输出Mod 1

二维的最长递增子序列问题。

有一些学生的成绩的数据,每个学生有sat和gpa成绩,如何找出一个最长的递增子序列,使得sat[1] < sat[2] < ... < sat[n] 且gpa[1] > gpa[2] > ... > gpa[n] 思路是做一次排序,对另一维使用传统的O(nlgn)的最长递增子序列的查找,只是找到了该学生可构成的最长递增子序列的长度d时,需要另外做一次判断,是否第一维和d-1长度的第一维是相等的. package Solution; public class Soluti

最长公共子序列(LCS)、最长递增子序列(LIS)、最长递增公共子序列(LICS)

最长公共子序列(LCS) [问题] 求两字符序列的最长公共字符子序列 问题描述:字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列.令给定的字符序列X=“x0,x1,…,xm-1”,序列Y=“y0,y1,…,yk-1”是X的子序列,存在X的一个严格递增下标序列<i0,i1,…,ik-1>,使得对所有的j=0,1,…,k-1,有xij=yj.例如,X=“ABCBDAB”,Y=“BCDB”是X的一个子序列. 考虑最长公共子序列问题如何分解成

最长递增子序列 &amp;&amp; 最大子序列、最长递增子序列、最长公共子串、最长公共子序列、字符串编辑距离

http://www.cppblog.com/mysileng/archive/2012/11/30/195841.html 最长递增子序列问题:在一列数中寻找一些数,这些数满足:任意两个数a[i]和a[j],若i<j,必有a[i]<a[j],这样最长的子序列称为最长递增子序列. 设dp[i]表示以i为结尾的最长递增子序列的长度,则状态转移方程为: dp[i] = max{dp[j]+1}, 1<=j<i,a[j]<a[i]. 这样简单的复杂度为O(n^2),其实还有更好的方

动态规划之最长递增子序列问题详解

最近重新开始看动态规划,动态规划算法的有效性依赖于问题本身所具有的两个重要性质:最优子结构性质和子问题重叠性质. 1.最优子结构:当问题的最优解包含了其子问题的最优解时,称该问题具有最优子结构性质. 2.重叠子问题:在用递归算法自顶向下解问题时,每次产生的子问题并不总是新问题,有些子问题被反复计算多次.动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只解一次,而后将其解保存在一个表格中,在以后尽可能多地利用这些子问题的解. (二).动态规划算法的基本步骤设计一个标准的动态规划算法,通常

最长递增子序列问题

题目描述 给定一个未排序的整数数组,找出最长递增子序列. 例如给定数组[10, 9, 2, 5, 3, 7, 101, 18],最长递增子序列就是[2, 3, 7, 101],长度就是4,最长递增子序列不一定只有一个,只要求出最长的长度. 解法一 动态规划法,定义一个数组dp,dp[i]代表了第i个数为结尾的最长递增子序列长度.当计算第dp[i]时,比较i位置的值和前面的所有值相比,如果值大于前面j处的值,就记录当前最大的dp[i]为dp[j]+1,dp[i]中的最大值.遍历过程中可以设置一个值