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

题意:给出N个矩形的左下角的点 (x1,y1) 、右上角的点 (x2,y2) 。定义矩形 AB ,当 A.x2<B.x1 A.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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值