zoukankan      html  css  js  c++  java
  • [四连测(二)]测量温度(temperature)

    题目描述

    某国进行了连续N(1<=N<=1000000)天的温度测量,测量存在误差,测量结果是第i天温度在[l_i,r_i]范围内。其中-10^9<l_i<=r_i<=10^9
    求最长的连续的一段,满足该段内可能温度不降

    输入

    第一行一个整数n。

    接下来n行,每一行两个整数,表示l_i和r_i。

    输出

    接下来输出一个整数,表示答案。

    样例输入

    6
    6 10
    1 5
    4 8
    2 5
    6 8
    3 5

    样例输出

    4

    解题思路

    首先解释一下题吧,我觉得题目还是有很多坑的(主要是考试的时候搞得我原地爆炸)

    第i天是有一个范围的,它可以取这个范围中的任意值。叫我们求最长连续的一段。为啥连续我要标红呢?因为我就以为它可能不连续,被绕了近2个小时。连续比不连续是要轻松非常多的。然而考试的时候没注意,白白浪费了时间,草草打了个暴搜还发现题都读错了。至于可能不降是什么意思呢,其实就是连续一段中每一天取任意的一个值只要能够保证序列不下降即可。

    题目理解了,那么便要想办法解决了。我们要让每一天的l值尽可能取到,这样才能尽可能多。然而连续一段中,有些天的温度下限较高,而我们尽可能要多,所以我们可以维持这一个下限,这样的话,第i天是否能算作是子序列中的一个那就要看第i天的上限是否大于i前面所有的下限的最大值了。

    也许你会想,这样不爆了?从1到n一重循坏,1到i又是一重了。数据范围肯定是不允许这样弄的。于是我们便要想到优化。单调队列的做法就这样出现了。

    首先,确定方法,由于判断i是否能进连续的子序列中需要用到i以前的温度下限最大值,所以我们维护单调队列呈递减,我们便仅仅需要与队头进行判断了。由于单调队列是要弹东西出去的。万一哪些弹出去的东西还有用呢?带一带数据,这是不存在的。因为是从1到n进行遍历的。如果中间有个下限不符合要求,那么前面的那些自然是不用考虑的,毕竟是要连续。

    但如果队头不合格呢?我们要能够快速得出答案,要不然这样将会十分麻烦。首先,对于不合格的队头,我们是要果断弹出去的,带一带数据也可以发现,如果不合格,在后面的天数中其实也是没有用的。然后要怎么求出合格的子序列的长度呢?其实也很简单,你最后一个弹出去的队头的后一个到I其实就是合格的。为什么这么说,其实跟遍历的顺序是有一定关系的(顿时发现这道题好多个重要的点)。这里就不再赘述。

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    #include<cstdlib>
    #include<queue>
    #include<vector>
    #include<stack>
     
    #define M 1000005
     
    using namespace std;
    int n , l[M] , r[M] , formation[M * 2] , head = 1 , tail = 1 , x , ans;
    int main(){
        //freopen("1.in","r",stdin);
        scanf ("%d",&n);
        scanf ("%d%d",&l[1],&r[1]);
        x = 1;
        ans = 1;
        formation[tail] = 1;
        for (int i = 2 ;i <= n ;i ++ ){
            scanf ("%d%d",&l[i],&r[i]);
        }
        for (int i = 2 ;i <= n; i ++ ){
            while (head <= tail && l[formation[head]] > r[i]){
                head ++ ;
            }
            if (head <= tail){   
                x = formation[head - 1];
                ans = max (ans ,i - x);
            }
            while (head <= tail )
                if (l[i] >= l[formation[tail]])
                    tail --;
                else
                    break;
            formation [++ tail ] = i;
        }
        printf("%d",ans);
    }

    总结

    看起来还是比较简单的吧。但考试时候对于这道题我真的是崩溃不已,一开始读错了题,很久都没想出来,后面看到了问题,却是没有多余的什么精力去打了。神奇的是我暴力出来的分竟还比一些同学的分高。他们考试的时候有一个点没有看到,以为仅仅跟前面的一个进行比较即可。这种情况我早就弄清楚了。然而苦推半天,依旧打不出什么。我觉得吧,也许我清楚了题目,至少还是能想到些方法的,就不会用什么暴力了。实现证明我的暴力程序还有WA的,暴力都没打好。太急躁了,没有读懂题意。虽然我也不一定能够在读懂题意的情况下做对,但我这次的确是犯了十分严重的错误。第一道题的问题直接影响我后面的题,后面的题基本没怎么在做。

    还是说一下题目本身的新颖思路吧。首先,我们全然没有考虑到:顺着这样遍历有这么多重要的点,这可以说是单调队列这样做思路的核心,说明数据还是非常重要的,一些好的数据可以让你发现其中的规律。觉得这道题就想是滑动窗口,只不过判定条件不同而已

  • 相关阅读:
    切分文本行
    oracle 导出【转】
    SQL 表A不在表B记录
    Oracle 数据库操作
    oracle 跨表更新
    WPF : ViewPort3D, ModelVisual3D XAML example
    WPF : 3D 最简单的WPF 3D
    WPF : StoryBoard用法
    WPF/SilverLight学习计划
    WPF : 3D 给GeometryModel3D对象贴图
  • 原文地址:https://www.cnblogs.com/lover-fucker/p/13566701.html
Copyright © 2011-2022 走看看