1. 程式人生 > >[四連測(二)]測量溫度(temperature)

[四連測(二)]測量溫度(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的,暴力都沒打好。太急躁了,沒有讀懂題意。雖然我也不一定能夠在讀懂題意的情況下做對,但我這次的確是犯了十分嚴重的錯誤。第一道題的問題直接影響我後面的題,後面的題基本沒怎麼在做。

還是說一下題目本身的新穎思路吧。首先,我們全然沒有考慮到:順著這樣遍歷有這麼多重要的點,這可以說是單調佇列這樣做思路的核心,說明資料還是非常重要的,一些好的資料可以讓你發現其中的規律。覺得這道題就想是滑動視窗,只不過判定條件不同而已