您的位置:首页 > 运维架构

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

2016-05-07 01:50 381 查看

题目链接:

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是随长度变大递增的!!!(这个可以证明!),于是就可以用二分来找能接在当前的那个人后面的最长的长度。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;

const int maxn = 1e5 + 10;

struct Node {
int x, y,id;
bool operator < (const Node& tmp) const {
return x < tmp.x||x==tmp.x&&y>tmp.y;
}
}arr[maxn];

int n,maxlen;
int pre[maxn],dp[maxn],yy[maxn];

void init() {
memset(pre, -1, sizeof(pre));
maxlen = 0;
}

int main() {
while (scanf("%d", &n) == 1 && n) {
init();
for (int i = 0; i < n; i++) {
scanf("%d%d", &arr[i].x, &arr[i].y);
arr[i].id = i + 1;
}
sort(arr, arr + n);
dp[0] = 1; yy[++maxlen] = 0;
for (int i = 1; i < n; i++) {
int low = 1, hig = maxlen+1;
if (arr[i].y <= arr[yy[low]].y) {
yy[low] = i;
continue;
}
while (low + 1 < hig) {
int mid = low + (hig - low) / 2;
if (arr[yy[mid]].y < arr[i].y) low = mid;
else hig = mid;
}
pre[i] = yy[low];
int len = low + 1;
if (len > maxlen) {
yy[++maxlen] = i;
}
else {
if (arr[i].y < arr[yy[len]].y) yy[len] = i;
}
}
vector<int> ans;
int p = yy[maxlen];
while (p != -1) {
ans.push_back(p);
p = pre[p];
}
printf("%d\n", ans.size());
for (int i = 0; i < ans.size() - 1; i++) printf("%d ", arr[ans[i]].id);
printf("%d\n", arr[ans[ans.size() - 1]].id);
}
return 0;
}


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

待续。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: