XDU-1107 Too Simple (DP)

1107: Too Simple

Time Limit: 2 Sec   Memory Limit: 128 MB
[ Submit][ Status][ Web Board]

Description

一棵n个点的树, 树上每个点有两个权值x ,y。 x, y都是整数。
现在要从树上选出尽可能多的点重新建边组成一棵新树, (仅仅一棵新树)。
新树要满足,树上任意两个点的权值(xi, yi), (xj, yj) 都满足xi < xjyi < yj 或者 满足xi > xj
yi > yj.输出新树最多能由多少个点组成。

Input

多组数据,处理到EOF 不超过10组
第一行整数n , 2 <= <= 100000
接下来两行 ,每行n个整数, 
第一行表示n个点的X权值 x1, x2, x3....xn, 空格隔开。
第二行表示n个点的Y权值, y1, y2, y3....yn,空格隔开。
0 < x, y < 100000000

Output

输出新树最多能有多少个点组成。

Sample Input

5
1 5 3 2 4
8 6 9 3 4

Sample Output

3

突然又想到3个月前还有几道题没有A掉,作为强迫症的我肯定忍不了。


第一反应又是O(n^2)的算法:排序(按x升序,再按y升序排序)后求最长上升子序列,TLE过果断放弃这个方法。

又想到排序后基本上类似于一维的最长上升子序列,便找到O(nlogn)的最长上升子序列算法学了一下。WA了,然后贪心删除x重复的点,狂WA十几发,一直以为是二分条件写搓了...躺在床上不久便想出贪心的反例,只得拖到第二天

早上起来激动地去掉贪心,继续连WA十几发,又以为是二分条件写搓了。

在不停的调试中,发现:这样排序的话,某些情况下会使最长的长度减少。

比如:

3

1 4 4

2 1 3

这组数据,

进行到(4,1)时,由于在(4,1)和(1,2)中,y值1<2,导致在最长上升子序列中,第1个点的最小值从(1,2)变为(4,1),从而使(4,3)无法更新最大长度。

刚开始没想到改排序方法,只是加了另一个数组,x相同的点,按y值降序遍历。

AC后想到可以直接按x升序,再按y降序排序,求最长上升子序列时,只用按下标遍历即可。


#include <cstdio>
#include <algorithm>
using namespace std;

struct Node {
    int x,y;
    bool operator < (const Node& a) const {
        return x<a.x||(x==a.x&&y>a.y);//按x升序,再按y降序排序
    }
}a[100005];

int mn[100005],n;

int LIS() {
    int ans=0,i,l,r,mid;
    for(i=1;i<=n;++i) {
        l=1,r=ans;
        while(l<=r) {//二分找到最大的y值小于关键值a[i].y的下标
            mid=(l+r)>>1;
            if(a[mn[mid]].y<a[i].y)
                l=mid+1;
            else
                r=mid-1;
        }
        if(l>ans)//如果最大的y值都比a[i].y小,更新最长的长度以及其下标
            mn[ans=l]=i;
        else if(a[mn[l]].y>a[i].y)
            mn[l]=i;
    }
    return ans;
}

int main() {
    int i;
    while(scanf("%d",&n)==1) {
        for(i=1;i<=n;++i)
            scanf("%d",&a[i].x);
        for(i=1;i<=n;++i)
            scanf("%d",&a[i].y);
        sort(a+1,a+n+1);
        printf("%d\n",LIS());
    }
    return 0;
}




你可能感兴趣的:(dp,xdu)