[四連測(二)]測量溫度(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天是有一個範圍的,它可以取這個範圍中的任意值。叫我們求最長連續
題目理解了,那麼便要想辦法解決了。我們要讓每一天的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的,暴力都沒打好。太急躁了,沒有讀懂題意。雖然我也不一定能夠在讀懂題意的情況下做對,但我這次的確是犯了十分嚴重的錯誤。第一道題的問題直接影響我後面的題,後面的題基本沒怎麼在做。
還是說一下題目本身的新穎思路吧。首先,我們全然沒有考慮到:順著這樣遍歷有這麼多重要的點,這可以說是單調佇列這樣做思路的核心,說明資料還是非常重要的,一些好的資料可以讓你發現其中的規律。覺得這道題就想是滑動視窗,只不過判定條件不同而已