zoukankan      html  css  js  c++  java
  • SPOJ 3943

    现在n(<=20000)个俄罗斯套娃,每个都有宽度wi和高度hi(均小于10000),要求w1<w2并且h1<h2的时候才可以合并,问最少能剩几个。

    【LIS】乍一看跟【这题】类似,但是仔细看是有区别的,其实就相当于上一题多次求LIS,每次求完LIS后把得到的序列删去,然后重新求LIS,最后输出求LIS的次数,我一开始这样写,果然就TLE了。还是要另辟蹊径。

    首先用贪心思想,先按照wi从大到小排序,wi相等的情况下hi从小到大,然后求最长不下降子序列(注意可以等于)。输出其长度即可。

    想想为什么,如果有i和j这两个点满足wi>wj,hi>hj,显然是满足条件的,直接合并即可(所求序列长度不变),但是如果wi>wj,hi<=hj不可合并,那么序列长度就要增加。

    如果wi==wj,那么无论hi与hj的关系如何都不可以合并,为了方便求最长不下降序列,可以假设hi<=hj,这样序列长度也会增加。因此wi相等的情况下hi要从小到大排序。

    还有一个问题是LIS中二分查找的写法问题,我是卡在了这里,在网上看了看别人的代码后,把lower_bound改成了upper_bound竟然AC了!

    lower_bound是返回序列中大于等于key值的第一个数

    upper_bound是返回序列中严格大于key值的第一个数

    显然最长上升子序列是严格递增的,因此每次更新后都不可以出现两个数相同的情况,因此使用lower_bound(比如1,2,3,4,新输入的数是3,使用lower_bound返回第三个数,即把3改成3,如果使用upper_bound返回第四个数,把4改成3,则会出现两个3,不符合条件)。而最长不下降子序列存在多个数相同的情况,因此使用upper_bound,这里解释同上。

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<stack>
    #include<vector>
    #include<queue>
    #include<string>
    #include<sstream>
    #define eps 1e-9
    #define ALL(x) x.begin(),x.end()
    #define INS(x) inserter(x,x.begin())
    #define FOR(i,j,k) for(int i=j;i<=k;i++)
    #define MAXN 20005
    #define MAXM 40005
    #define INF 0x3fffffff
    using namespace std;
    typedef long long LL;
    int i,j,k,n,m,x,y,T,ans,big,cas,num,len;
    bool flag;
    
    struct node
    {
        int s,b,i;
    }p[MAXN];
    
    int dp[MAXN];
    
    bool cmp(node x,node y)
    {
        if (x.s==y.s) return x.b<y.b;
        return x.s>y.s;
    }
    
    int main()
    {
        scanf("%d",&T);
        while (T--)
        {
            scanf("%d",&n);
            
            for (i=1;i<=n;i++)
            {
                scanf("%d%d",&p[i].s,&p[i].b);
                p[i].i=i;
            }
            sort(p+1,p+1+n,cmp);
        
            num=0;
            for (i=1;i<=n;i++)//求最长不下降子序列
            {
                if (p[i].b>=dp[num])//与最长上升子序列求法不同的是这里改成大于等于
                {
                    dp[++num]=p[i].b;
                }else
                {
                    k=upper_bound(dp+1,dp+1+num,p[i].b)-dp; //与最长上升子序列求法不同的是这里改成upperbound
                    
                    dp[k]=p[i].b;
                }
            }
            
            printf("%d
    ",num);
        }
        return 0;
    }
  • 相关阅读:
    Docker常用命令总结(不断更新)
    Docker容器简介-与虚拟机的区别及安装步骤
    ELK搭建—安装使用Kibana可视化
    使用CURL与ElasticSearch服务进行通信
    安装部署ElasticSearch单节点在Linux服务器上
    ElasticStack分布式引擎技术栈(ELK)介绍
    为Nginx服务器配置黑(白)名单的防火墙
    php大力力 [026节] php开发状态要随时做好整理工作
    php大力力 [025节] 来不及学习和分类的,大力力认为有价值的一些技术文章合集(大力力二叔公)(2015-08-27)
    php大力力 [024节]PHP中的字符串连接操作(2015-08-27)
  • 原文地址:https://www.cnblogs.com/zhyfzy/p/4285473.html
Copyright © 2011-2022 走看看