• 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
    ", ans.size());
    61         for (int i = 0; i < ans.size() - 1; i++) printf("%d ", arr[ans[i]].id);
    62         printf("%d
    ", arr[ans[ans.size() - 1]].id);
    63     }
    64     return 0;
    65 }

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

    待续。。。

  • 相关阅读:
    例6-5
    例7-1+7-2
    例6-2+6-3
    习题二(3)
    习题二(1)
    课堂作业4
    课堂作业3
    实验三 利用循环计算n个圆柱体体积。
    实验三 编写求圆面积的程序,要求当输入的半径r<=0时,提示输入错误,要求r为浮点型,r的数值是动态的由键盘输入;
    心得3
  • 原文地址:https://www.cnblogs.com/fenice/p/5467627.html
Copyright © 2020-2023  润新知