BOJ 171 6th I 单调队列优化DP

来源:互联网 发布:淘宝商家怎么贷款 编辑:程序博客网 时间:2024/06/11 02:36

题意:给出N个矩形的左下角的点(x1,y1)、右上角的点(x2,y2)。定义矩形AB ,当A.x2<B.x1A.y2<B.y1
求出最长的矩形序列A1,A2,...,An,满足A1A2A3...An.
思路:可以看到,定义的AB关系不满足自反性,所以是个DAG上的动态规划。
但是可以计算得到,朴素的动态规划是Θ(n2),明显会超时。
这样看来,必须要优化。
注意到满足题意的矩形序列的点的值是对于x,对于y,都是递增的,可以想到对单调上升子序列的单调队列的优化。
我们首先固定一维x,即将所有点按照x从小到大进行排序。
然后考虑另外的一维y。
和单调上升子序列的单调队列一样,我们定义dp[i]为长度为i的矩形序列的右上角的点yd的最小值。
这样,对于矩形的左下角的点,我们需要找到在dp[i]中更新的位置。
对于矩阵的右上角的点,我们要更新dp[i]中的值。
这样,查找和更新的分离就能完成这道题目了。
最后的结果就是dp数组中,有效数字的数目,同样也可以二分找到。

注意:二元小于运算符的判断写跪了。。。学了一个神奇的姿势。

#include <cstdio>#include <algorithm>#include <cstring>using namespace std;const int MAX = 100010;const int INF = 0x3f3f3f3f;struct point{    int x, y, id,flag;    point(){}    point(int a, int b, int c,int d): x(a), y(b), id(c),flag(d){}    bool operator <(const point & rhs) const{        return (x < rhs.x) || (!(rhs.x < x) && (flag < rhs.flag));    }} p[MAX<<1];int pos[MAX<<1], dp[MAX<<1];int main(void){    //freopen("input.txt","r",stdin);    int T,N;    scanf("%d",&T);    while(T--){        scanf("%d",&N);        for(int i = 0; i < N; ++i){            int a,b,c,d;            scanf("%d%d%d%d",&a,&b,&c,&d);            p[i<<1] = point(a,b,i,0);            p[i<<1|1] = point(c,d,i,1);        }        N *= 2;        sort(p,p + N);        memset(dp,0x3f,sizeof(dp));        for(int i = 0; i < N; ++i){            if(p[i].flag == 0)                pos[p[i].id] = lower_bound(dp,dp + N, p[i].y) - dp;            else                dp[pos[p[i].id]] = min(dp[pos[p[i].id]],p[i].y);        }        printf("%d\n",lower_bound(dp,dp+N,INF) - dp);    }    return 0;}
0 0
原创粉丝点击